Parte 3 de la serie "Seguridad web en la UE: 10 pasos para una mejor calificación"
Por qué importa CSP
Cross-Site Scripting (XSS) ha sido la vulnerabilidad de aplicaciones web más común durante más de 20 años. Un atacante inyecta JavaScript en tu sitio web — mediante un formulario, un parámetro de URL, un comentario. El navegador del visitante ejecuta el código porque no puede distinguirlo del contenido legítimo de la página.
Content Security Policy (CSP) resuelve este problema: defines explícitamente qué fuentes puede aceptar el navegador para scripts, estilos, imágenes y otros recursos. Todo lo demás se bloquea.
Tasa de adopción en la UE: 10,8%. Nueve de cada diez sitios web no tienen cabecera CSP.
Qué dicen los datos
Del Benchmark SiteGuardian con más de 700.000 sitios web europeos:
- 10,8% tiene una cabecera CSP
- Los sitios web con security.txt tienen CSP en el 47% de los casos — 4,7 veces más frecuente
- Permissions-Policy (cabecera relacionada): solo 6,4%
Desplegar CSP paso a paso
El mayor obstáculo: una CSP demasiado estricta rompe el sitio. Google Analytics deja de cargar, los vídeos embebidos de YouTube desaparecen, los estilos en línea dejan de funcionar.
Paso 1: Modo Report-Only (no rompe nada)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
El navegador informa de las violaciones pero no bloquea nada. Ves qué fuentes externas usa tu sitio sin romper nada.
Paso 2: Identificar las fuentes
Supervisa los informes durante 1-2 semanas. Fuentes típicas que necesitarás permitir:
- Google Analytics:
https://www.googletagmanager.com https://www.google-analytics.com - Google Fonts:
https://fonts.googleapis.com https://fonts.gstatic.com - Vídeos de YouTube:
https://www.youtube.com https://www.youtube-nocookie.com - Tu CDN:
https://cdn.tu-dominio.com
Paso 3: Construir la política
Content-Security-Policy: default-src 'self'; script-src 'self' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data: https:; frame-src https://www.youtube-nocookie.com
Paso 4: Activar
Elimina -Report-Only del nombre de la cabecera. Prueba el sitio exhaustivamente.
Directivas clave
| Directiva | Controla | Recomendación |
|---|---|---|
default-src |
Respaldo para todo | 'self' |
script-src |
JavaScript | 'self' + dominios explícitos |
style-src |
CSS | 'self' 'unsafe-inline' (a menudo necesario) |
img-src |
Imágenes | 'self' data: https: |
font-src |
Fuentes | 'self' + Google Fonts si es necesario |
connect-src |
XHR/Fetch | 'self' + dominios de API |
frame-src |
iframes | Solo dominios explícitos |
object-src |
Flash/Java | 'none' (siempre) |
base-uri |
etiqueta base | 'self' |
Nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; object-src 'none'; base-uri 'self'" always;
Apache
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; object-src 'none'; base-uri 'self'"
Errores comunes
1. unsafe-inline para scripts. script-src 'unsafe-inline' permite cualquier script en línea — anulando completamente la CSP contra XSS. Usa nonces o hashes en su lugar.
2. * como fuente. default-src * permite todo desde cualquier lugar. Eso no es una política, es un placebo.
3. Empezar demasiado estricto. Siempre comienza con Report-Only. Una CSP que rompe el sitio y se desactiva inmediatamente no protege a nadie.
Contexto regulatorio
- NIS2 Art. 21(2)(d) — seguridad en el desarrollo y mantenimiento de sistemas de información
- RGPD Art. 32 — XSS puede llevar a brechas de datos (secuestro de sesión, robo de cookies)
- PCI DSS 4.0 — El requisito 6.4.3 exige explícitamente CSP para las páginas de pago
Comprueba tu CSP
SiteGuardian no solo detecta si existe una cabecera CSP, sino que analiza las directivas en busca de debilidades conocidas:
La próxima semana en la Parte 4: DNSSEC — por qué el 84% de los dominios de la UE no tiene protección contra DNS spoofing.