¿Cómo funciona la Política de seguridad de contenidos (CSP)?
Recibo un montón de errores en la consola del desarrollador:
Se negó a evaluar una cadena
Se negó a ejecutar el script en línea porque viola la siguiente directiva de política de seguridad de contenido
Se negó a cargar el script
Se negó a cargar la hoja de estilo.
¿De qué se trata todo esto? ¿Cómo funciona la Política de seguridad de contenidos (CSP)? ¿Cómo uso el Content-Security-Policy
encabezado HTTP?
Específicamente, ¿cómo...?
- ...permitir múltiples fuentes?
- ...utilizar directivas diferentes?
- ...¿utilizar varias directivas?
- ...manejar puertos?
- ...manejar diferentes protocolos?
- ...permitir
file://
protocolo? - ...utilizar estilos, scripts y etiquetas en línea
<style>
y<script>
? - ...permitir
eval()
?
Y finalmente:
- ¿Qué significa exactamente
'self'
?
La Content-Security-Policy
metaetiqueta le permite reducir el riesgo de ataques XSS al permitirle definir desde dónde se pueden cargar los recursos, evitando que los navegadores carguen datos desde otras ubicaciones. Esto hace que sea más difícil para un atacante inyectar código malicioso en su sitio.
Me golpeé la cabeza contra una pared de ladrillos tratando de descubrir por qué recibía errores de CSP uno tras otro, y no parecía haber instrucciones claras y concisas sobre cómo funciona. Así que aquí está mi intento de explicar brevemente algunos puntos de CSP, concentrándome principalmente en las cosas que encontré difíciles de resolver.
Por brevedad, no escribiré la etiqueta completa en cada muestra. En lugar de eso, solo mostraré la content
propiedad, por lo que un ejemplo que dice content="default-src 'self'"
significa esto:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
1. ¿Cómo puedo permitir múltiples fuentes?
Simplemente puede enumerar sus fuentes después de una directiva como una lista separada por espacios:
content="default-src 'self' https://example.com/js/"
Tenga en cuenta que no hay comillas alrededor de parámetros distintos de los especiales , como 'self'
. Además, no hay dos puntos ( :
) después de la directiva. Solo la directiva, luego una lista de parámetros separados por espacios.
Todo lo que esté por debajo de los parámetros especificados está permitido implícitamente. Eso significa que en el ejemplo anterior estas serían fuentes válidas:
https://example.com/js/file.js
https://example.com/js/subdir/anotherfile.js
Éstos, sin embargo, no serían válidos:
http://example.com/js/file.js
^^^^ wrong protocol
https://example.com/file.js
^^ above the specified path
2. ¿Cómo puedo utilizar diferentes directivas? ¿Qué hace cada uno?
Las directivas más comunes son:
default-src
la política predeterminada para cargar javascript, imágenes, CSS, fuentes, solicitudes AJAX, etc.script-src
define fuentes válidas para archivos javascriptstyle-src
define fuentes válidas para archivos cssimg-src
define fuentes válidas para imágenesconnect-src
define objetivos válidos para XMLHttpRequest (AJAX), WebSockets o EventSource. Si se realiza un intento de conexión a un host que no está permitido aquí, el navegador emulará un400
error
Hay otros, pero estos son los que probablemente necesitarás.
3. ¿Cómo puedo utilizar varias directivas?
Defina todas sus directivas dentro de una metaetiqueta finalizándolas con un punto y coma ( ;
):
content="default-src 'self' https://example.com/js/; style-src 'self'"
4. ¿Cómo puedo manejar los puertos?
Todo, excepto los puertos predeterminados, debe permitirse explícitamente agregando el número de puerto o un asterisco después del dominio permitido:
content="default-src 'self' https://ajax.googleapis.com http://example.com:123/free/stuff/"
Lo anterior daría como resultado:
https://ajax.googleapis.com:123
^^^^ Not ok, wrong port
https://ajax.googleapis.com - OK
http://example.com/free/stuff/file.js
^^ Not ok, only the port 123 is allowed
http://example.com:123/free/stuff/file.js - OK
Como mencioné, también puedes usar un asterisco para permitir explícitamente todos los puertos:
content="default-src example.com:*"
5. ¿Cómo puedo manejar diferentes protocolos?
De forma predeterminada, sólo se permiten protocolos estándar. Por ejemplo, para permitir WebSockets ws://
tendrás que permitirlo explícitamente:
content="default-src 'self'; connect-src ws:; style-src 'self'"
^^^ web Sockets are now allowed on all domains and ports.
6. ¿Cómo puedo permitir el protocolo de archivo file://
?
Si intentas definirlo como tal, no funcionará. En su lugar, lo permitirás con el filesystem
parámetro:
content="default-src filesystem"
7. ¿Cómo puedo utilizar scripts en línea y definiciones de estilo?
A menos que se permita explícitamente, no puede utilizar definiciones de estilo en línea, código dentro de <script>
etiquetas o en propiedades de etiquetas como onclick
. Les permites así:
content="script-src 'unsafe-inline'; style-src 'unsafe-inline'"
También tendrás que permitir explícitamente imágenes codificadas en base64 en línea:
content="img-src data:"
8. ¿Cómo puedo permitirlo eval()
?
Estoy seguro de que mucha gente diría que no, ya que 'eval es malo' y la causa más probable del inminente fin del mundo. Esa gente estaría equivocada. Claro, definitivamente puedes perforar agujeros importantes en la seguridad de tu sitio con eval, pero tiene casos de uso perfectamente válidos. Sólo hay que ser inteligente al usarlo. Lo permites así:
content="script-src 'unsafe-eval'"
9. ¿Qué significa exactamente 'self'
?
Puede que te 'self'
refieras a localhost, sistema de archivos local o cualquier cosa en el mismo host. No significa nada de eso. Significa fuentes que tienen el mismo esquema (protocolo), el mismo host y el mismo puerto que el archivo en el que se define la política de contenido. ¿Sirve su sitio a través de HTTP? Entonces no hay https para ti, a menos que lo definas explícitamente.
Lo he usado 'self'
en la mayoría de los ejemplos porque normalmente tiene sentido incluirlo, pero de ninguna manera es obligatorio. Déjalo fuera si no lo necesitas.
¡Pero espera un minuto! ¿No puedo simplemente usarlo content="default-src *"
y terminar con él?
No. Además de las obvias vulnerabilidades de seguridad, esto tampoco funcionará como cabría esperar. Aunque algunos médicos afirman que permite cualquier cosa, eso no es cierto. No permite inlining o evals, por lo que para realmente hacer que su sitio sea más vulnerable, usaría esto:
content="default-src * 'unsafe-inline' 'unsafe-eval'"
... pero confío en que no lo harás.
Otras lecturas:
http://content-security-policy.com
http://en.wikipedia.org/wiki/Content_Security_Policy
Apache 2 mod_headers
También puedes habilitar Apache 2 mod_headers. En Fedora ya está habilitado de forma predeterminada. Si usas Ubuntu/Debian, habilítalo así:
# First enable headers module for Apache 2,
# and then restart the Apache2 service
a2enmod headers
apache2 -k graceful
En Ubuntu/Debian puedes configurar encabezados en el archivo
/etc/apache2/conf-enabled/security.conf
#
# Setting this header will prevent MSIE from interpreting files as something
# else than declared by the content type in the HTTP headers.
# Requires mod_headers to be enabled.
#
#Header set X-Content-Type-Options: "nosniff"
#
# Setting this header will prevent other sites from embedding pages from this
# site as frames. This defends against clickjacking attacks.
# Requires mod_headers to be enabled.
#
Header always set X-Frame-Options: "sameorigin"
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Permitted-Cross-Domain-Policies "master-only"
Header always set Cache-Control "no-cache, no-store, must-revalidate"
Header always set Pragma "no-cache"
Header always set Expires "-1"
Header always set Content-Security-Policy: "default-src 'none';"
Header always set Content-Security-Policy: "script-src 'self' www.google-analytics.com adserver.example.com www.example.com;"
Header always set Content-Security-Policy: "style-src 'self' www.example.com;"
Nota: Esta es la parte inferior del archivo. Sólo las últimas tres entradas son configuraciones de CSP.
El primer parámetro es la directiva, el segundo son las fuentes que se incluirán en la lista blanca. Agregué Google Analytics y un servidor de anuncios, que quizás tengas. Además, descubrí que si tienes alias, por ejemplo, www.example.com y example.com configurados en Apache 2, también debes agregarlos a la lista blanca.
El código en línea se considera dañino y debes evitarlo. Copie todo el código JavaScript y CSS en archivos separados y agréguelos a la lista blanca.
Mientras lo hace, puede echar un vistazo a las otras configuraciones del encabezado e instalar mod_security
Otras lecturas:
https://developers.google.com/web/fundamentals/security/csp/
https://www.w3.org/TR/CSP/