Generador de Content Security Policy
Genera encabezados Content-Security-Policy.
Build a Content-Security-Policy. Common keywords: 'self' 'none' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' data: https: blob:
Descripción general
Una Content-Security-Policy le dice al navegador de qué orígenes puede cargar recursos. Su valor práctico es más estrecho de lo que sugiere el nombre: la CSP no arregla el cross-site scripting, lo contiene. Si una inyección se cuela por tu codificación de salida, una política estricta es lo que impide que el script inyectado se ejecute o que envíe lo que ha robado al servidor de un atacante.
La cabecera es una lista de directivas separadas por punto y coma, cada una con un tipo de recurso y los orígenes que se le permiten. Esta herramienta te da un campo por directiva, rellena una política de partida razonable y muestra la cabecera montada mientras escribes.
Cómo se usa
- Arranca desde la política prerrellenada:
default-src 'self',object-src 'none',base-uri 'self',frame-ancestors 'none'. Es un suelo razonable para un sitio que sirve sus propios recursos. - Añade los orígenes que de verdad necesitas, una directiva a la vez. Separa varios orígenes con espacios.
- Deja una directiva en blanco para omitirla; las directivas en blanco recurren
a
default-src. - Copia la cabecera y despliégala primero como
Content-Security-Policy-Report-Only. Lee los informes de violación, corrige la política y luego cambia al nombre de cabecera que aplica de verdad.
Las palabras clave de origen
| Palabra clave | Significado |
|---|---|
'self' | El propio origen del documento: mismo esquema, host y puerto |
'none' | Nada en absoluto. Solo tiene sentido como único origen |
'unsafe-inline' | Permite <script> / <style> en línea y manejadores de eventos en línea |
'unsafe-eval' | Permite eval, new Function y argumentos de cadena en setTimeout |
'strict-dynamic' | Confía en los scripts creados por un script ya confiable. Hace que se ignoren las listas de hosts de esa directiva |
data: | Permite URI data:. Razonable en img-src, peligroso en script-src |
https: | Cualquier origen sobre HTTPS. Amplísimo: suele ser señal de que la política necesita afinarse |
blob: | Permite URL blob:, necesarias para Web Workers creados a partir de código generado |
Los hashes ('sha256-…') y los nonces ('nonce-…') son las alternativas
estrictas a 'unsafe-inline'. Un hash cubre un script en línea concreto cuyo
contenido no cambia nunca, lo que encaja con los sitios generados estáticamente.
Un nonce es un valor aleatorio nuevo en cada respuesta, lo que encaja con las
páginas renderizadas en el servidor. No puedes usar un nonce en un hosting de
archivos estáticos, porque no hay ningún paso por petición donde generarlo.
Las directivas que es fácil equivocar
base-uri no lo cubre default-src. Sin ella, una etiqueta <base href>
inyectada puede redirigir todas las URL relativas de la página al host de un
atacante —incluidas tus etiquetas de script— sin llegar a inyectar ningún
script. Ponla en 'self' o en 'none'.
form-action tampoco la cubre default-src. Sin ella, un formulario
inyectado puede enviar lo que escriban tus usuarios a otro origen.
frame-ancestors sustituye a X-Frame-Options. Cuando las dos se
contradicen, los navegadores modernos siguen la CSP, así que poner solo la
cabecera antigua deja a los navegadores más nuevos sin ninguna de las
restricciones que querías expresar.
object-src 'none' vale la pena ponerlo de forma explícita. El contenido de
plugins es una vía de ejecución heredada sin ningún uso legítimo en un sitio
nuevo.
connect-src es la que se olvida todo el mundo. Gobierna fetch, XHR, los
WebSockets y sendBeacon, que es exactamente por donde un script inyectado
exfiltraría datos. Un script-src apretado con un connect-src abierto de par
en par deja abierta la puerta que pretendía cerrar.
Ejemplos
Un sitio estático que sirve sus propios recursos y no tiene scripts de terceros:
default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none';
form-action 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:;
font-src 'self'; connect-src 'self'; upgrade-insecure-requests
El mismo sitio con una etiqueta de analítica, permitiendo solo los orígenes
concretos que necesita en lugar de https::
script-src 'self' https://www.googletagmanager.com;
connect-src 'self' https://www.google-analytics.com
Recoger los informes de violación
El modo Report-Only solo sirve si lees los informes. Existen dos mecanismos, y el soporte de los navegadores está partido, así que un despliegue suele enviar los dos.
report-uri /csp-report es la directiva más antigua. Está obsoleta pero sigue
siendo la de soporte más amplio, y publica un cuerpo JSON que describe el
recurso bloqueado, la directiva que lo bloqueó y la URL del documento.
report-to es su sustituta. Nombra un grupo de informes configurado mediante una
cabecera de respuesta Reporting-Endpoints aparte, lo que permite que un mismo
endpoint reciba juntos los informes de CSP, de obsolescencia y de intervención.
Cualquiera que uses, cuenta con ruido. Las extensiones del navegador inyectan
scripts y estilos en las páginas, y sus violaciones se ven idénticas a las tuyas
en el informe. La señal es una violación que aparece para muchos usuarios
distintos sobre la misma URL de documento y la misma directiva; un
blocked-uri aislado que apunta a un esquema chrome-extension: es el gestor de
contraseñas de alguien.
Ninguna de las dos directivas está disponible en una etiqueta <meta>. Los
informes requieren la cabecera HTTP de verdad.
Notas
upgrade-insecure-requests reescribe las peticiones de subrecursos http:// a
https:// antes de hacerlas. Es una ayuda para migrar páginas con contenido
mixto, no un sustituto de arreglar las URL, y no se aplica a la navegación hacia
otros sitios.
style-src suele ser el último 'unsafe-inline' en caer, y a menudo el que vale
la pena conservar. Los atributos style en línea no se pueden cubrir con un
hash —necesitarías 'unsafe-hashes' más un hash por cada valor de atributo
distinto— y la inyección de CSS es un problema mucho más estrecho que la
inyección de scripts. Gastar el esfuerzo primero en script-src es el mejor
canje.
Despliega con Content-Security-Policy-Report-Only antes de aplicar la política
de verdad. Una política que se pasa de estricta por una sola directiva no se
degrada con elegancia: rompe la página en silencio para todos los visitantes cuyo
navegador la aplique, y te enterarás por los usuarios y no por tus propias
pruebas.
Si quieres comprobar qué envía ahora mismo un sitio en producción, el verificador de cabeceras HTTP muestra las cabeceras de respuesta de cualquier URL.