Identifica los vectores de XSS propios del marcado y despliega las defensas nativas de HTML: sandbox, noopener y Content Security Policy.
Abrir esta lección en KodokonEl contexto de escape marca toda la diferencia: un valor inofensivo en un nodo de texto se vuelve ejecutable en un atributo. El atributo sin comillas es el peor caso: un solo espacio en los datos inyectados basta para crear un nuevo atributo, por ejemplo un manejador onmouseover. Incluso cuando está correctamente entrecomillado, un valor sigue siendo peligroso en sinks sensibles: href y src aceptan el esquema javascript:, formaction secuestra el envío de un formulario, y srcdoc interpreta sus entidades como HTML una vez decodificadas.
<!-- userName = x onmouseover=alert(1) -->
<img src="avatar.png" alt=x onmouseover=alert(1)>
<!-- The unquoted attribute lets a handler in -->El atributo sandbox de un iframe elimina todos los privilegios, y luego los vuelves a otorgar uno por uno: allow-scripts, allow-forms, allow-popups... Sin allow-same-origin, el documento incrustado recibe un origen opaco: sin cookies, sin almacenamiento, sin acceso al DOM del padre - incluso si se sirve desde tu propio dominio.
<iframe
src="https://widget.example.com"
sandbox="allow-scripts allow-forms"
referrerpolicy="no-referrer">
</iframe>Un enlace target=_blank daba históricamente a la página abierta una referencia window.opener a tu pestaña: podía redirigir tu página a un clon de phishing, el ataque conocido como tabnabbing. Los navegadores modernos ahora aplican noopener de forma implícita en target=_blank, pero deletrearlo sigue siendo esencial para window.open en JavaScript y para documentar la intención; añade noreferrer para suprimir también la cabecera Referer.
<a href="https://external.example"
target="_blank"
rel="noopener noreferrer">
View the external resource
</a>Una Content Security Policy restringe las fuentes de código ejecutable y neutraliza la mayoría de los XSS, incluso cuando la inyección ha tenido éxito. Declarada mediante una etiqueta <meta http-equiv>, tiene sin embargo puntos ciegos: las directivas frame-ancestors, report-uri y sandbox se ignoran ahí y requieren la cabecera HTTP. Prefiere nonces regenerados en cada respuesta antes que listas de dominios permitidos, que la directiva strict-dynamic vuelve obsoletas de todos modos.
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'nonce-r4nd0m'">allow-scripts y allow-same-origin en un iframe del mismo origen anula el sandbox?rel=noopener?window.opener para redirigir tu pestaña a un sitio de phishing<meta http-equiv>?