Prevenir la inyección de JavaScript no es una sola tarea. Es cerrar varias puertas distintas que conducen todas a la misma sala: código controlado por un atacante ejecutándose en los navegadores de tus visitantes con todos los privilegios de tu propia página. Algunas de esas puertas son errores en tu código. La mayoría son scripts que cargaste deliberadamente y que luego se volvieron hostiles. Esta guía recorre los controles que realmente reducen el riesgo, en el orden que ofrece más protección con el menor esfuerzo, y es honesta sobre dónde se detiene cada control.
Si primero quieres el contexto, qué es la inyección de JavaScript cubre el mecanismo y todas las vías por las que el código ajeno entra en una página. Este artículo es la continuación práctica: qué hacer al respecto.
Cómo prevenir la inyección de JavaScript, en resumen
- Cierra la clase XSS en tu propio código. Codifica en la salida, usa sinks del DOM seguros, sanea el HTML no confiable y activa Trusted Types.
- Restringe de dónde puede provenir el script. Una Content Security Policy estricta basada en nonce bloquea los orígenes de script no autorizados.
- Fija lo que puedas. Subresource Integrity congela las dependencias estáticas de terceros a un hash conocido.
- Reduce el árbol de dependencias. Cada script de terceros que eliminas es una vía de inyección menos.
- Monitoriza el tiempo de ejecución. Vigila cada script que se ejecuta en sesiones reales del navegador, porque la prevención no puede alcanzar el compromiso de un proveedor de confianza.
Las vías de inyección contra las que te defiendes
La prevención solo tiene sentido cuando sabes qué estás previniendo. El JavaScript se inyecta por cuatro vías amplias, y cada una exige un control distinto:
| Vía de inyección | Cómo ocurre | El control que ayuda |
|---|---|---|
| Cross-site scripting (XSS) | Un fallo en tu código permite que la entrada del atacante se ejecute como script | Codificación de salida, sinks seguros, saneamiento, Trusted Types |
| Script de terceros comprometido | Un proveedor cuyo tag cargas distribuye código malicioso | Revisión de dependencias, CSP, Subresource Integrity, monitorización en ejecución |
| Magecart / skimmers | Los atacantes plantan código para robar tarjetas en páginas de pago, a menudo vía una dependencia comprometida | Monitorización de la carga en ejecución en el checkout, controles PCI DSS |
| Extensiones maliciosas / malware del cliente | El código se inyecta en la propia máquina del visitante, en cada sitio que visita | Detección en ejecución; no puedes parchear el navegador del visitante |
La primera vía es un fallo de código que te pertenece y puedes corregir. El resto son fallos de confianza: el código fue invitado, o vive en una máquina que no controlas. Esa división importa, porque explica por qué corregir tu propio código es necesario pero nunca suficiente.
Paso 1: Cierra la clase XSS en tu propio código
El cross-site scripting es la única vía de inyección que está enteramente bajo tu control, así que empieza aquí. El XSS ocurre cuando un dato que suministra un usuario se escribe en la página en un lugar donde el navegador lo tratará como código en lugar de texto. Las correcciones están bien entendidas:
- Codifica en la salida, no solo en la entrada. La misma cadena es segura en un contexto y peligrosa en otro, así que codifica los datos para el contexto exacto donde aterrizan: cuerpo HTML, atributo HTML, JavaScript, URL o CSS. La codificación de salida consciente del contexto es el control anti-XSS más eficaz.
- Usa sinks del DOM seguros. Asigna datos no confiables con
textContenten vez deinnerHTML, y evitaeval,document.writeysetAttributesobre manejadores de eventos. Estos "sinks" son donde las cadenas inyectadas se vuelven ejecutables. - Sanea el HTML que debas renderizar. Cuando realmente necesites renderizar HTML suministrado por el usuario (un comentario con texto enriquecido, por ejemplo), pásalo por un saneador mantenido que elimine el script y los manejadores de eventos, en vez de escribir tu propio filtro.
- Activa Trusted Types. Trusted Types hacen que los sinks peligrosos del DOM rechacen cadenas simples a nivel del navegador, de modo que una carga inyectada no puede alcanzarlos aunque un error se cuele en la revisión de código. Se aplica mediante una directiva de CSP, lo que conduce directamente al siguiente paso.
Corregir la clase XSS elimina la puerta que un atacante abre explotando tu código. No hace nada respecto a las puertas que abriste tú mismo al cargar el script de otro, que es de donde proviene la mayoría de las brechas modernas del lado del cliente.
Paso 2: Restringe los orígenes con una Content Security Policy
Una Content Security Policy le indica al navegador qué orígenes están autorizados a cargar y ejecutar script en tu página. Una CSP estricta basada en nonce es uno de los controles individuales más fuertes que puedes desplegar contra la inyección: el script que no proviene de un origen permitido, y que no lleva el nonce correcto por solicitud, simplemente no se ejecuta. Los bloques <script> en línea que un atacante inyecta a través de un agujero XSS se bloquean por defecto.
Dos notas prácticas. Primero, prefiere los nonces a las listas de hosts permitidos siempre que puedas; una lista amplia de script-src reabre en silencio vías que pretendías cerrar. Segundo, y este es el límite importante: la CSP autoriza orígenes, no juzga el comportamiento. Una vez que autorizas el dominio de un proveedor para que su script legítimo se ejecute, la CSP no tiene forma de saber si ese script se está portando bien o robando datos de tu formulario. Si el proveedor está comprometido en el origen, su dominio sigue en tu lista de permitidos y la versión maliciosa se carga limpiamente. La CSP es necesaria. No es la respuesta completa.
Paso 3: Fija las dependencias estáticas con Subresource Integrity
Subresource Integrity (SRI) te permite adjuntar un hash criptográfico a un tag <script> o <link>. El navegador calcula el hash del archivo que descargó y se niega a ejecutarlo si el hash no coincide, lo que significa que un archivo estático de terceros no puede ser reemplazado por una versión manipulada sin que el cambio se bloquee.
SRI es excelente para dependencias que no cambian: una versión específica de una biblioteca fijada a su hash exacto. Su límite es la imagen especular de esa fortaleza. No hace nada por los scripts que están pensados para actualizarse (la mayoría de las analíticas, los gestores de tags y los SDK de pago cambian su archivo servido con regularidad), y no hace nada por los scripts cargados dinámicamente por otros scripts. Usa SRI en todas partes donde puedas fijar una versión. No esperes que cubra las partes de tu pila que se actualizan solas.
Paso 4: Reduce y revisa el árbol de dependencias
Cada script de terceros en tu página es una vía de inyección con todos los privilegios de la página. La prevención más barata disponible es tener menos de ellos.
- Inventaría lo que realmente cargas. A la mayoría de los equipos les sorprende cuántos scripts se ejecutan en una página típica, y cuántos se cargan no directamente sino por otro script (un gestor de tags que carga un proveedor que carga otro proveedor).
- Elimina lo que no necesitas. Un píxel de marketing sin uso o una herramienta de pruebas A/B abandonada es puro riesgo sin beneficio. Borrarlo elimina una vía de inyección por completo.
- Minimiza el radio de impacto del gestor de tags. Una cuenta de gestor de tags comprometida puede inyectar "solo otro tag" que parece rutinario. Restringe quién puede publicar y revisa lo que publica.
Este paso no tiene desventaja y ningún control por script puede sustituirlo: un script que no está en la página no puede ser el que se vea comprometido.
Paso 5: Monitoriza el tiempo de ejecución con inspección de la carga en sesiones reales
Los pasos del uno al cuatro reducen la probabilidad. Ninguno puede alcanzar el caso que causa las peores brechas del lado del cliente: un script en el que confías legítimamente, de un origen que permitiste legítimamente, que se vuelve malicioso después de estar ya cargado. La CSP lo deja pasar porque el origen está permitido. SRI lo pierde porque el script está diseñado para actualizarse. Tu propio código está limpio. El único lugar que queda para atraparlo es donde la inyección aterriza realmente, el navegador, en el momento en que el script se ejecuta.
Eso es lo que hace la monitorización en tiempo de ejecución. Construye un inventario de cada script que se ejecuta en sesiones reales de usuario, registra lo que hace cada uno y a dónde envía datos, y alerta cuando aparece un script nuevo, cambia el código de un script conocido o los datos empiezan a fluir hacia un destino inesperado. Esta es la capa que atrapa los skimmers de tipo Magecart y los ataques de proveedores comprometidos que todos los controles preventivos anteriores dejan pasar.
Las herramientas del lado del servidor no pueden proporcionar esto. Un firewall de aplicaciones web o un escaneo del servidor ve el HTML que enviaste, no la carga que un proveedor comprometido cambia después ni el código que una extensión inyecta en la máquina del visitante. La detección tiene que ocurrir en la capa del navegador, en sesiones reales.
Dónde encaja cside: monitorización de scripts en sesiones reales
cside es un único script de JavaScript propio (first-party) que proporciona la capa en tiempo de ejecución de esta lista de comprobación. No reemplaza tu CSP, tu codificación de salida ni tus hashes de SRI; es el control que vigila lo que tus scripts permitidos hacen realmente una vez que están ejecutándose, algo que ninguno de los otros puede ver.
La monitorización de scripts de cside inventaría cada script que se ejecuta en sesiones reales del navegador, analiza la carga completa del script y alerta sobre dominios nuevos, código modificado y flujos de datos inesperados. Funciona en dos modelos operativos: el Script Method obtiene y analiza los scripts de terceros del lado de cside antes de que se ejecuten en la sesión, y el Scan Method para equipos que prefieren una huella más ligera. Se despliega como un solo tag de script desde tu propio origen, sin cambios de DNS; cside obtiene y analiza los scripts de terceros que carga tu página, pero no se sitúa delante del tráfico de tu sitio y no actúa como un proxy.
En las páginas de pago este inventario en tiempo de ejecución también es un requisito de cumplimiento. Los requisitos 6.4.3 y 11.6.1 de PCI DSS 4.0.1 existen precisamente porque el script inyectado en la página de pago es invisible para todos los controles del lado del servidor: 6.4.3 te pide gestionar y autorizar cada script en tus páginas de pago, y 11.6.1 te pide detectar cambios no autorizados en esos scripts y en las cabeceras de la página. La monitorización de scripts en sesiones reales es la respuesta directa a ambos.
Lista de comprobación de prevención
La prevención de la inyección de JavaScript es por capas, y las capas no se solapan:
- Codifica la salida y usa sinks del DOM seguros para cerrar la clase XSS en tu propio código.
- Despliega una CSP estricta basada en nonce para bloquear los orígenes de script no autorizados.
- Añade Subresource Integrity para fijar las dependencias estáticas de terceros.
- Reduce y revisa el árbol de dependencias para que haya menos que comprometer.
- Monitoriza sesiones reales del navegador para que un script de confianza que se vuelve hostil se atrape en el momento en que actúa.
Acierta con los primeros cuatro y habrás cerrado la mayoría de las puertas. Añade el quinto y podrás ver la única puerta que la prevención nunca puede cerrar del todo: el proveedor de confianza que se ve comprometido después de que lo dejaste entrar.









