XSS


¿Qué es XSS?

XSS (Cross-Site Scripting) es una vulnerabilidad de seguridad web que permite a atacantes inyectar y ejecutar scripts maliciosos en páginas web visitadas por otros usuarios. Esta vulnerabilidad ocurre cuando una aplicación web incluye datos no validados o no escapados en sus páginas, permitiendo que código JavaScript malicioso se ejecute en el navegador de las víctimas sin su conocimiento.

¿Para qué se utiliza XSS?

XSS es explotado por atacantes maliciosos para:

  • Robar cookies de sesión y tokens de autenticación para hacerse pasar por otros usuarios.
  • Capturar información sensible como contraseñas, datos personales o información financiera.
  • Redirigir usuarios a sitios web maliciosos o de phishing.
  • Modificar el contenido de páginas web para mostrar información falsa o dañina.
  • Instalar malware o keyloggers en el navegador de la víctima.
  • Realizar acciones no autorizadas en nombre del usuario autenticado (cambiar contraseñas, realizar transferencias, etc.).

¿Cómo funciona?

Imagina XSS como un ventrílocuo malicioso que logra que el sitio web “hable” con la voz del atacante. El sitio web de confianza termina ejecutando código que no escribió, como si fuera suyo propio. Los usuarios confían en el sitio web, pero sin saberlo, están ejecutando código del atacante en sus navegadores con todos los privilegios del sitio legítimo.

Ejemplo: Vulnerabilidad XSS básica

Aquí tienes ejemplos de cómo ocurre XSS y cómo prevenirlo:

<!-- VULNERABLE: Sin validación ni escape -->
<div class="comentarios">
    <h3>Comentarios de usuarios</h3>
    <?php
    // MALO: Directamente imprime input del usuario
    foreach ($comentarios as $comentario) {
        echo "<p>Usuario: " . $comentario['nombre'] . "</p>";
        echo "<p>Mensaje: " . $comentario['mensaje'] . "</p>";
    }
    ?>
</div>

<!-- Si un atacante envía este comentario: -->
<!-- nombre: <script>alert('XSS!');</script> -->
<!-- Se ejecutará el JavaScript en el navegador de todos los visitantes -->

<!-- SEGURO: Con validación y escape -->
<div class="comentarios">
    <h3>Comentarios de usuarios</h3>
    <?php
    // BUENO: Escapa caracteres especiales
    foreach ($comentarios as $comentario) {
        echo "<p>Usuario: " . htmlspecialchars($comentario['nombre'], ENT_QUOTES, 'UTF-8') . "</p>";
        echo "<p>Mensaje: " . htmlspecialchars($comentario['mensaje'], ENT_QUOTES, 'UTF-8') . "</p>";
    }
    ?>
</div>

Este ejemplo muestra cómo un input malicioso puede ejecutar JavaScript y cómo prevenirlo escapando caracteres especiales.

Ejemplo: Prevención XSS en JavaScript moderno

// VULNERABLE: Manipulación directa del DOM
function mostrarMensaje(userInput) {
    // MALO: innerHTML con datos no validados
    document.getElementById('mensaje').innerHTML = `
        <div class="alerta">
            <h4>Mensaje del usuario:</h4>
            <p>${userInput}</p>
        </div>
    `;
}

// SEGURO: Sanitización y escape apropiado
function mostrarMensajeSeguro(userInput) {
    // BUENO: textContent escapa automáticamente
    const container = document.getElementById('mensaje');
    container.innerHTML = ''; // Limpiar contenido previo
    
    const alertDiv = document.createElement('div');
    alertDiv.className = 'alerta';
    
    const titulo = document.createElement('h4');
    titulo.textContent = 'Mensaje del usuario:';
    
    const mensaje = document.createElement('p');
    mensaje.textContent = userInput; // textContent previene XSS
    
    alertDiv.appendChild(titulo);
    alertDiv.appendChild(mensaje);
    container.appendChild(alertDiv);
}

// ALTERNATIVA: Usar librerías de sanitización
function mostrarMensajeConLibreria(userInput) {
    // Usando DOMPurify para sanitizar HTML
    const cleanHTML = DOMPurify.sanitize(userInput);
    document.getElementById('mensaje').innerHTML = `
        <div class="alerta">
            <h4>Mensaje del usuario:</h4>
            <div>${cleanHTML}</div>
        </div>
    `;
}

// Validación de entrada adicional
function validarEntrada(input) {
    // Longitud máxima
    if (input.length > 500) {
        throw new Error('Mensaje demasiado largo');
    }
    
    // Lista negra de patrones sospechosos
    const patronesPeligrosos = [
        /<script[\s\S]*?>[\s\S]*?<\/script>/gi,
        /javascript:/gi,
        /on\w+\s*=/gi,
        /<iframe[\s\S]*?>[\s\S]*?<\/iframe>/gi
    ];
    
    for (const patron of patronesPeligrosos) {
        if (patron.test(input)) {
            throw new Error('Contenido no permitido detectado');
        }
    }
    
    return input;
}

// Uso seguro
try {
    const userInput = validarEntrada(document.getElementById('userComment').value);
    mostrarMensajeSeguro(userInput);
} catch (error) {
    console.error('Error de validación:', error.message);
    mostrarError('Por favor, revisa tu mensaje');
}

Tipos de XSS

  • Reflected XSS: El script malicioso se refleja inmediatamente en la respuesta HTTP.
  • Stored XSS: El script se almacena en el servidor y se ejecuta cada vez que se carga la página.
  • DOM-based XSS: La vulnerabilidad existe en el código JavaScript del lado del cliente.
  • Blind XSS: El payload se almacena y ejecuta en un panel administrativo u otra interfaz.

Medidas de prevención XSS

// 1. Content Security Policy (CSP)
// En el HTML head:
/* 
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';">
*/

// 2. Validación de entrada
function validarEmail(email) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
}

// 3. Escape de salida contextual
function escapeHTML(str) {
    const div = document.createElement('div');
    div.textContent = str;
    return div.innerHTML;
}

function escapeCSS(str) {
    return str.replace(/[<>"'&\\]/g, function(match) {
        switch(match) {
            case '<': return '\\3C ';
            case '>': return '\\3E ';
            case '"': return '\\22 ';
            case "'": return '\\27 ';
            case '&': return '\\26 ';
            case '\\': return '\\5C ';
            default: return match;
        }
    });
}

// 4. Usar librerías de sanitización
// npm install dompurify
import DOMPurify from 'dompurify';

function sanitizeUserContent(htmlContent) {
    return DOMPurify.sanitize(htmlContent, {
        ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],
        ALLOWED_ATTR: []
    });
}

// 5. Configurar cookies seguras
document.cookie = "sessionId=abc123; Secure; HttpOnly; SameSite=Strict";

¿Dónde encuentras vulnerabilidades XSS?

  • En formularios de comentarios y sistemas de chat sin validación adecuada.
  • En barras de búsqueda que reflejan el término buscado sin escape.
  • En perfiles de usuario donde se puede personalizar información mostrada públicamente.
  • En paneles administrativos que muestran datos ingresados por usuarios.
  • En aplicaciones que procesan URLs o parámetros GET sin validación.
  • En sistemas de notificaciones que muestran contenido generado por usuarios.

Herramientas de detección XSS

# Análisis estático de código
npm install -g eslint-plugin-security
eslint --ext .js,.jsx src/ --plugin security

# Pruebas automatizadas
npm install --save-dev @security/eslint-plugin
npm install --save-dev jest-dom-security

# Escáners de vulnerabilidades web
# OWASP ZAP
# Burp Suite
# XSStrike

Conclusión

XSS es una de las vulnerabilidades web más comunes y peligrosas que puede comprometer completamente la seguridad de usuarios y aplicaciones. La prevención efectiva requiere una combinación de validación de entrada, escape de salida contextual, Content Security Policy, y el uso de librerías de sanitización confiables. Todo desarrollador web debe entender XSS y implementar medidas de seguridad desde el diseño de la aplicación.


Usamos cookies para mejorar tu experiencia. ¿Aceptas las cookies de análisis?