Una política de seguridad de contenido (CSP) bien definida es una de las defensas más eficaces contra el cross-site scripting (XSS) y la inyección de datos. Esta herramienta le permite construir la cabecera paso a paso, aplicar presets para servicios habituales como Google AdSense, Analytics o Stripe, y exportar la configuración lista para Nginx, Apache o Cloudflare Workers.
Un validador analiza la política en tiempo real y señala configuraciones peligrosas, como 'unsafe-inline' o 'unsafe-eval', antes de que lleguen a producción.
¿Qué es Content-Security-Policy y por qué importa?
Content-Security-Policy (CSP) es una cabecera de respuesta HTTP con la que el servidor indica al navegador qué orígenes están autorizados a cargar scripts, estilos, imágenes, fuentes, marcos y conexiones de red en una página. Si un atacante logra inyectar código en el HTML (por ejemplo, a través de una vulnerabilidad de cross-site scripting), el navegador bloqueará la ejecución o la carga de todo lo que la política no permita. La CSP no sustituye a la validación de entradas ni al escape de salidas en el servidor, pero reduce de forma drástica el impacto de los fallos que se escapan a esos controles.
Cómo evalúa el navegador una política
Cada tipo de recurso está gobernado por una directiva específica. Cuando esa directiva no existe, el navegador recurre a default-src. De forma simplificada, la decisión para cada recurso es la siguiente:
permitido = origen ∈ lista(directiva específica), si la directiva está definida.permitido = origen ∈ lista(default-src), si la directiva específica no está definida.- Si no existe ninguna política aplicable, el recurso se permite sin restricciones.
Tres directivas no heredan de default-src: base-uri, form-action y frame-ancestors. Si no se declaran, quedan sin restricción. Cuando una página recibe varias políticas (por ejemplo, una cabecera y una etiqueta meta), todas se aplican y un recurso solo se carga si cumple cada una de ellas; el resultado equivale a la intersección de las políticas.
Directivas que configura esta herramienta
default-src: política de respaldo para todos los tipos de recurso que no tengan directiva propia.script-src: controla el JavaScript. Es la directiva más importante frente a XSS.style-src: hojas de estilo y bloques de estilo inline.img-srcyfont-src: imágenes y tipografías.connect-src: destinos defetch, XHR, WebSocket y similares.frame-srcyframe-ancestors: qué contenido puede incrustar su página y quién puede incrustar la suya (defensa contra clickjacking).object-src,base-uriyform-action: cierran vectores clásicos de inyección con plugins, etiquetas<base>y formularios.
Tipos de fuente
'none': no permite nada. Es el valor correcto paraobject-src.'self': solo el mismo origen (esquema, host y puerto).- Hosts concretos como
https://js.stripe.com: la opción recomendada para servicios de terceros. https:o*: demasiado amplias; permiten cargar desde casi cualquier sitio.'nonce-…'y'sha256-…': autorizan scripts inline concretos sin recurrir a'unsafe-inline'.'strict-dynamic': confía en los scripts cargados por un script ya autorizado con nonce o hash.
Otras cabeceras de seguridad que conviene desplegar
Strict-Transport-Security (HSTS) obliga al navegador a usar HTTPS. El valor habitual de un año se calcula como max-age = 365 × 24 × 3600 = 31536000 segundos. Para entrar en la lista de precarga de los navegadores se exige además includeSubDomains y preload, y conviene hacerlo solo cuando todo el dominio y sus subdominios funcionen por HTTPS, porque revertirlo es lento.
X-Frame-Options (DENY o SAMEORIGIN) protege a navegadores antiguos frente al clickjacking; frame-ancestors es su equivalente moderno. X-Content-Type-Options: nosniff impide que el navegador reinterprete el tipo MIME de una respuesta. Permissions-Policy desactiva funciones del navegador como cámara, micrófono o geolocalización. Referrer-Policy limita la información de origen que se envía en las peticiones salientes.
Despliegue paso a paso sin romper producción
- Active el modo Report-Only: la cabecera
Content-Security-Policy-Report-Onlynotifica las infracciones sin bloquear nada. - Revise la consola del navegador y los informes recibidos, y añada solo las fuentes legítimas que falten.
- Elimine
'unsafe-inline'y'unsafe-eval'sustituyéndolos por hashes o nonces y refactorizando el código que dependa de ellos. - Cambie a la cabecera
Content-Security-Policyen modo de aplicación y mantenga la monitorización activa.
Casos de uso reales
- Sitio de contenidos con AdSense y Analytics: los presets añaden los hosts de Google necesarios. Los fragmentos de inicialización son inline, por lo que se recomienda empezar en Report-Only y estudiar los informes.
- Tienda con Stripe: el preset autoriza
js.stripe.comenscript-srcyframe-src, yapi.stripe.comenconnect-src. - Panel SaaS interno: una política estricta con
default-src 'self',frame-ancestors 'none'y HSTS reduce la superficie de ataque ante auditorías de seguridad. - Sitio estático detrás de Cloudflare: el resultado puede exportarse como Cloudflare Worker que añade las cabeceras a todas las respuestas sin tocar el origen.
Errores habituales
- Usar
https:enscript-srccreyendo que es seguro: permite scripts de cualquier host HTTPS. - Permitir CDN públicas con contenido controlable por terceros, que pueden servir para eludir la política.
- Olvidar
base-uri,object-srcyform-action, que no heredan dedefault-srco dejan vectores abiertos. - Confiar en la etiqueta meta para todo: no admite
frame-ancestors,report-urinisandbox.