Comprendiendo la vulnerabilidad XSS: principios, detección y defensa en aplicaciones web

La vulnerabilidad de Cross-Site Scripting (XSS) permite a los atacantes inyectar scripts maliciosos en páginas web vistas por otros usuarios. El núcleo del problema radica en que la aplicación web trata la entrada del usuario como código ejecutable en lugar de texto seguro.

Principios fundamentales de XSS

Los frameworks modernos como Vue y React implementan mecanismos de escape automático. Vue escapa el contenido HTML de forma predeterminada en las plantillas, pero el uso de v-html requiere precaución. React escapa todos los cadenas antes de la renderización, sin embargo, dangerouslySetInnerHTML omite esta protección.

El punto crítico es que el navegador no puede distinguir entre código legítimo y scripts inyectados. La vulnerabilidad se materializa en el momento de la salida de datos al HTML, no en la entrada.

<!-- Código vulnerable: entrada del usuario concatenada directamente -->
<div>Bienvenido, <%= usuarioInput %></div>

<!-- Entrada maliciosa: -->
<script>alert('XSS!')</script>

Clasificación de ataques XSS

Tipo XSS Persistente XSS Reflejado XSS basado en DOM
Característica El script se almacena en el servidor El script está en la URL Se ejecuta compeltamente en el cliente
Payload típico <img src=x onerror=alert(1)> ';alert(1);// http://ejemplo.com#<img src=x onerror=alert(1)>

Ejemplos prácticos por tipo

XSS persistente

// Almacenamiento sin validación (Node.js)
app.post('/comentarios', (req, res) => {
  bd.guardarComentario(req.body.texto);
});

// Renderización vulnerable
app.get('/comentarios', (req, res) => {
  const comentarios = bd.obtenerComentarios();
  res.send(comentarios.map(c => `<div>${c.texto}</div>`));
});

XSS basado en DOM y mutaciones (mXSS)

El mXSS ocurre cuando datos de usuario sufren múltiples renderizaciones DOM, causando distorsiones sintácticas que el navegador repara, potencialmente convirtiendo contenido "seguro" en código ejecutable.

<div id="contenedor-1"></div>
<div id="contenedor-2"></div>
<script>
  const entrada = '<scr<script>ipt>alert("mXSS")</script>';
  const contenedor1 = document.getElementById('contenedor-1');
  
  contenedor1.innerHTML = entrada; // El navegador repara la sintaxis
  const contenidoDistorsionado = contenedor1.innerHTML;
  
  document.getElementById('contenedor-2').innerHTML = contenidoDistorsionado;
</script>

XSS en analizadores UBB

Los sistemas UBB que no filtran protocolos peligrosos son vulnerables:

function analizarUBB(contenido) {
  return contenido.replace(/\[img\](.*?)\[\/img\]/gi, 
    '<img src="$1" alt="imagen">');
}

// Entrada maliciosa: [img]javascript:alert(1)[/img]

Prácticas seguras en frameworks

Vue.js

// Evitar v-html con contenido no confiable
<div v-html="contenidoSanitizado"></div>

<script>
import DOMPurify from 'dompurify';

export default {
  computed: {
    contenidoSanitizado() {
      return DOMPurify.sanitize(this.contenidoCrudo);
    }
  }
}
</script>

React

// Usar renderizado seguro por defecto
function ComponenteSeguro({ texto }) {
  return <div>{texto}</div>;
}

// Para contenido HTML, sanitizar primero
import DOMPurify from 'dompurify';

function HTMLSanitizado({ html }) {
  const limpio = DOMPurify.sanitize(html);
  return <div dangerouslySetInnerHTML={{ __html: limpio }} />;
}

Técnicas de detección

Pruebas manuales con payloads comunes

const payloadsPrueba = [
  '<script>alert(1)</script>',
  '<img src=x onerror=alert(1)>',
  'javascript:alert(1)',
  '\'";alert(1)//',
  '%26%23x3c;script%26%23x3e;'
];

Automatización con herramientas

Utilizar herramientas como Burp Suite para escaneo activo o XSS Hunter para captura automáticca de vulnerabiliaddes.

Defensa contra XSS

Política de Seguridad de Contenido (CSP)

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; 
               script-src 'self' https://cdn.confiable.com;
               style-src 'self' 'unsafe-inline';">

Sanitización en el servidor

function escaparHTML(cadena) {
  const mapa = {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'};
  return cadena.replace(/[<>"&]/g, m => mapa[m]);
}

Configuración segura de cookies

// Java - Spring Security
cookie.setSecure(true);
cookie.setHttpOnly(true);
cookie.setSameSite("Strict");

// Node.js - Express
res.cookie('session', valor, {
  secure: true,
  httpOnly: true,
  sameSite: 'strict'
});

Verificación de defensas

  1. Comprobar encabezados HTTP para CSP
  2. Verificar atributos HttpOnly en cookies
  3. Probar que las entradas se escapen al renderizarse

Etiquetas: XSS seguridad-web vue.js React DOM

Publicado el 6-26 00:09