Ingeniería civil y estructural
Cómo utilizar Javascript para detectar e prevenir ataques de scripting (xss)
Table of Contents
Introducción a la escritura cruzada (XSS) y a las defensas JavaScript
El scripting cruzado (XSS) es una de las vulnerabilidades de seguridad web más frecuentes, clasificando constantemente en el OWASP Top 10. Un ataque XSS permite que un atacante inyecte scripts maliciosos del lado del cliente en páginas web vistas por otros usuarios. Estos scripts pueden robar fichas de sesión, redirigir usuarios a sitios de phishing, páginas desfavorables o instalar malware.
Comprender los tres tipos de XSS
Antes de sumergirse en la prevención, es esencial entender las tres categorías primarias de XSS: almacenadas, reflejadas y basadas en DOM. Cada una requiere un enfoque de detección y prevención ligeramente diferente.
Almacenado XSS
Se almacena (persistente) XSS cuando la entrada maliciosa se almacena permanentemente en el servidor (por ejemplo, en una base de datos, correo del foro o comentario) y posteriormente se sirve a los usuarios sin la correcta sanitización. La carga de ataque se ejecuta en el navegador de cualquiera que vea el contenido almacenado.
XSS reflejado
El XSS reflejado ocurre cuando el script malicioso se refleja en un servidor web, normalmente a través de un parámetro URL o la presentación de formularios. El atacante engaña a una víctima para hacer clic en un enlace elaborado, y el código inyectado ejecuta inmediatamente. A diferencia de XSS almacenado, la carga útil no persiste.
DOM-Based XSS
XSS basado en DOM es una vulnerabilidad puramente del lado cliente. La carga útil de ataque modifica el entorno DOM en el navegador de la víctima. El código malicioso nunca toca el servidor; se origina desde el JavaScript del lado cliente que maneja inseguramente la entrada del usuario (por ejemplo, lectura de ], , o ).
Detectar XSS Ataques con JavaScript
La detección se trata de identificar actividad sospechosa antes de que ocurra el daño. Puede monitorear las entradas de los usuarios, rastrear las mutaciones de DOM y validar los datos en los puntos de entrada. Mientras que la detección del lado cliente no puede capturar todos los ataques (especialmente si el atacante solicita directamente al servidor), proporciona una valiosa primera línea de defensa.
Validación de entrada y saneamiento
Siempre validar y sanitizar las entradas de los usuarios en el lado cliente antes de procesar. Use en lugar de para prevenir la ejecución de script. La siguiente función tira caracteres peligrosos de una cadena:
function sanitizeInput(input) {
const div = document.createElement('div');
div.textContent = input;
return div.innerHTML;
}
Esto funciona porque el ajuste no interpreta etiquetas HTML; trata todo como texto llano. El resultado contiene versiones escapadas de cualquier caracteres especiales HTML (por ejemplo, ], , ].
Monitoreo de Mutaciones DOM para elementos sospechosos
Los atacantes suelen inyectar etiquetas o manipuladores de eventos (], ]) en el DOM. Usando la API , puedes ver las inserciones de elementos inesperados. Un ejemplo básico:
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === 1) { // element node
if (node.tagName === 'SCRIPT') {
console.warn('Potential XSS: a script element was injected via DOM.');
node.remove(); // or log and analyze
}
// Check for dangerous attributes
if (node.hasAttribute('onerror') || node.hasAttribute('onload')) {
console.warn('Suspicious event handler attribute detected.');
}
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
]Caution:] Los scripts bloqueantes pueden ser pasados por los atacantes inteligentes y pueden romper la funcionalidad legítima. Use esto como una herramienta de monitoreo en lugar de un mecanismo de prevención primaria.
Validación de URL y parámetros de Hash
Para XSS basado en DOM, lea los componentes de URL con seguridad utilizando y evite insertar directamente los valores en HTML. Detecta intentos de pasar código ejecutable:
const params = new URLSearchParams(window.location.search);
const userParam = params.get('name');
if (userParam && /[<>"'\/]/.test(userParam)) {
console.warn('Potential XSS in parameter: ' + userParam);
// Do not use this value in the DOM without encoding
}
Prevención de ataques XSS con JavaScript
La prevención requiere un enfoque multicapa. Solo el JavaScript no puede asegurar una aplicación completamente, pero cuando se combina con la sanitización adecuada de backend y Política de Seguridad de Contencioso (CSP), reduce drásticamente el riesgo.
codificar todos los datos controlados por el usuario antes de insertar en DOM
La regla de oro: nunca inserte datos no confiados directamente en el DOM. Utilice métodos DOM seguros en lugar de interiorHTML.
Usa o
const userInput = getUserInput();
const safeText = document.createTextNode(userInput);
document.getElementById('output').appendChild(safeText);
Cuando usted debe utilizar , Sanitize con una biblioteca
Si usted absolutamente necesita para renderizar HTML (por ejemplo, de un editor de texto rico), confíe en una biblioteca de saneamiento de confianza como DOMPurify. DOMPurify es una biblioteca ampliamente utilizada, de prueba de batalla que elimina el código malicioso al tiempo que preserva el HTML seguro.
// Example with DOMPurify (install via npm or CDN)
const dirty = '<img src=x onerror="alert(1)">';
const clean = DOMPurify.sanitize(dirty);
document.getElementById('content').innerHTML = clean;
DOMPurify works by parsing the input, stripping dangerous tags and attributeds, and returning only allowed elements. Ver DOMPurify on GitHub.
Evite las funciones peligrosas de JavaScript
Algunos métodos y propiedades JavaScript son notorios para permitir XSS. Evite o controle estrictamente:
- — use o sanitize adecuadamente.
- ], ] — misma regla.
- — nunca se utiliza con la entrada del usuario.
- ] — puede ser explotado si se concatena cualquier entrada.
- / con código de cadenas ] — evitar; utilizar referencias de función en su lugar.
- constructor — análogo a .
Implementar la Política de Seguridad de Contenidos (CSP) a través de JavaScript?
CSP es un mecanismo del navegador que restringe qué scripts pueden ejecutar. Se establece normalmente a través de encabezados HTTP, pero también se puede configurar mediante una etiqueta o mediante JavaScript mediante la creación dinámica de un elemento . Sin embargo, establecer CSP en JavaScript es menos seguro porque un atacante que ya tiene algún control podría desactivarlo.
const meta = document.createElement('meta');
meta.httpEquiv = 'Content-Security-Policy';
meta.content = "default-src 'self'; script-src 'self' 'unsafe-inline'"; // Be very careful with 'unsafe-inline'
document.head.appendChild(meta);
Para la producción, configure CSP en su servidor web o proxy inverso. ]La documentación de CSP de MDN proporciona una orientación completa.
Medidas adicionales de seguridad
Más allá de las tácticas específicas de JavaScript, una estrategia completa de prevención XSS incluye estas medidas críticas:
- Siempre validar en el lado servidor. La validación de lado del cliente puede ser pasada por alto. Nunca confíe en los datos del cliente.
- Usar cabeceras de respuesta adecuadas de HTTP. ], ], y especialmente ].
- ] Código de salida cada vez que usted hace datos de usuario.] Cuestiones de contexto: codificación para entidades HTML, codificación URL, codificación de cadenas JavaScript, etc.
- Mantenga dependencias actualizadas. Las bibliotecas JavaScript Vulnerable (por ejemplo, versiones anteriores de jQuery) son un vector XSS común. Utilice la auditoría de npm o herramientas similares.
- Use marcos con protección XSS integrada. React, Angular y Vue escapen automáticamente por defecto. Aún así, sea prudente con o ].
- Implement a strict CSP. Evite y ] si es posible. Use noces o hashes para scripts inline.
Ejemplo en el mundo real: Rendering de comentarios seguros
Considere un sistema de comentarios de blog donde los usuarios envían mensajes que se muestran a otros. Un atacante puede intentar insertar . Aquí hay un enfoque JavaScript que se integra con el backend:
- Frontend submission: Sanitize using antes de enviar al servidor (pero el servidor todavía debe sanitizar).
- Server devuelve los datos: El backend debe codificar el texto del comentario.
- Rendición de la pista: Usa o un motor de plantilla seguro. Nunca utilice con datos de usuario crudos.
function renderComment(comment) {
const item = document.createElement('div');
item.className = 'comment';
const body = document.createElement('p');
body.textContent = comment.body; // escaped by browser
item.appendChild(body);
document.getElementById('comments').appendChild(item);
}
Probando sus defensas
Después de implementar la prevención, prueba tu aplicación usando escáneres automáticos y cargas de pago manuales.
Utilice herramientas de desarrollador del navegador para examinar la DOM y asegurar que se escapen las cargas de pago. Además, probar la aplicación de CSP comprobando la consola para informes de violación.
Conclusión
El script cruzado sigue siendo una amenaza seria, pero JavaScript ofrece herramientas poderosas tanto para la detección como para la prevención. Al validar entradas, monitorear cambios DOM, escapar de la salida e integrar con bibliotecas robustas como DOMPurify, puede endurecer significativamente su seguridad del lado cliente. Recuerde que las medidas del lado del cliente no son una bala de plata; complementan una estrategia de defensa en profundidad que incluye la sanitización del lado del servidor, los encabezados CSP y las auditorías de seguridad regulares.
Para más lectura, consulte la página de WASP XSS y la .