¿Cómo funciona la Política de seguridad de contenido?

248

Recibo muchos errores en la consola del desarrollador:

Se negó a evaluar una cadena

Se negó a ejecutar un 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 contenido? ¿Cómo uso el Content-Security-Policyencabezado HTTP?

Específicamente, cómo ...

  1. ... permitir múltiples fuentes?
  2. ... usa diferentes directivas?
  3. ... usa múltiples directivas?
  4. ... manejar puertos?
  5. ... manejar diferentes protocolos?
  6. ... permitir file://protocolo?
  7. ... usa estilos en línea, guiones y etiquetas <style>y <script>?
  8. ... permitir eval()?

Y finalmente:

  1. ¿Qué 'self'significa exactamente ?
Schlaus
fuente

Respuestas:

557

La Content-Security-Policymetaetiqueta 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 cualquier otra ubicación. Esto dificulta que un atacante inyecte código malicioso en su sitio.

Me golpeé la cabeza contra una pared de ladrillos tratando de averiguar por qué estaba recibiendo 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, principalmente concentrándome en las cosas que encontré difíciles de resolver.

Por brevedad, no escribiré la etiqueta completa en cada muestra. En cambio, solo mostraré la contentpropiedad, por lo que una muestra que dice content="default-src 'self'"significa esto:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'">

1. ¿Cómo 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 por debajo de los parámetros especificados está implícitamente permitido. 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

Estos, 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 usar diferentes directivas, qué hacen cada una?

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 javascript
  • style-src define fuentes válidas para archivos CSS
  • img-src define fuentes válidas para imágenes
  • connect-srcdefine 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á un 400error

Hay otros, pero estos son los que es más probable que necesites.

3. ¿Cómo usar múltiples directivas?

Defina todas sus directivas dentro de una metaetiqueta terminándolas con un punto y coma ( ;):

content="default-src 'self' https://example.com/js/; style-src 'self'"

4. ¿Cómo manejar los puertos?

Todo menos 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 resultaría en:

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 puede usar un asterisco para permitir explícitamente todos los puertos:

content="default-src example.com:*"

5. ¿Cómo manejar diferentes protocolos?

Por defecto, solo se permiten protocolos estándar. Por ejemplo, para permitir WebSockets ws://, deberá 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 permitir el protocolo de archivo file://?

Si intentas definirlo como tal, no funcionará. En cambio, lo permitirá con el filesystemparámetro:

content="default-src filesystem"

7. ¿Cómo usar scripts en línea y definiciones de estilo?

A menos que se permita explícitamente, no puede usar definiciones de estilo en línea, código dentro de <script>etiquetas o en propiedades de etiqueta como onclick. Los permites así:

content="script-src 'unsafe-inline'; style-src 'unsafe-inline'"

También tendrá que permitir explícitamente imágenes codificadas en línea base64:

content="img-src data:"

8. ¿Cómo permitir eval()?

Estoy seguro de que mucha gente diría que no, ya que 'eval es malvado' y la causa más probable del inminente fin del mundo. Esas personas estarían equivocadas. Claro, definitivamente puede perforar agujeros importantes en la seguridad de su sitio con eval, pero tiene casos de uso perfectamente válidos. Solo tienes que ser inteligente al usarlo. Lo permites así:

content="script-src 'unsafe-eval'"

9. ¿Qué 'self'significa exactamente ?

Puede 'self'significar localhost, sistema de archivos local o cualquier cosa en el mismo host. No significa ninguno de esos. 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? No hay https para usted, a menos que lo defina explícitamente.

Lo he usado 'self'en la mayoría de los ejemplos, ya que generalmente tiene sentido incluirlo, pero de ninguna manera es obligatorio. Déjalo afuera si no lo necesitas.

¡Pero espera un minuto! ¿No puedo usarlo content="default-src *"y terminar con eso?

No. Además de las vulnerabilidades de seguridad obvias, esto tampoco funcionará como cabría esperar. Aunque algunos documentos afirman que permite cualquier cosa, eso no es cierto. No permite inlining o evals, por lo que realmente, realmente hace 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

Schlaus
fuente
66
Buena publicación. Una cosa: no es obvio lo que sucede cuando se especifican varias directivas; ¿La configuración style-src del ejemplo 3 tiene prioridad sobre default-src? etc ...
track0
30
Por lo tanto, para permitir que todo todo todo el contenido seríadefault-src *; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'; img-src * data: 'unsafe-inline'; connect-src * 'unsafe-inline'; frame-src *;
Arnold Roa
8
Es importante saber que content="default-src * 'unsafe-inline' 'unsafe-eval'"es necesario para que algunas aplicaciones angulares funcionen.
flanger001
2
@Mahesh Ese "blog" está lleno de publicaciones copiadas de SO. Parece poco probable que muchos usuarios de SO copien contenido de un blogger desconocido. Sé que no lo hice.
Schlaus
2
Nota breve sobre connect-srcy rutas: las barras diagonales finales son obligatorias si desea incluir una ruta secundaria completa. Por ejemplo: el archivo http://foo.com/files/bar.txtse bloqueará si la fuente es http://foo.com/files, pero se http://foo.com/files/
publicará
15

APACHE2 MOD_HEADERS

También puede habilitar Apache2 mod_headers, en Fedora ya está habilitado por defecto, si usa Ubuntu / Debian habilítelo así:

# First enable headers module for Apache2, 
# 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, solo las últimas 3 entradas son configuraciones CSP.

El primer parámetro es la directiva, el segundo son las fuentes que se incluirán en la lista blanca. He agregado Google Analytics y un servidor de anuncios, que podría tener. Además, descubrí que si tiene alias, por ejemplo, www.example.com y example.com configurados en Apache2, también debe agregarlos a la lista blanca.

El código en línea se considera dañino, debe evitarlo. Copie todos los javascripts y css para separar los archivos y agréguelos a la lista blanca.

Mientras lo hace, puede echar un vistazo a las otras configuraciones de encabezado e instalar mod_security

Otras lecturas:

https://developers.google.com/web/fundamentals/security/csp/

https://www.w3.org/TR/CSP/

Erik Hendriks
fuente
2
Pude agregar esas mismas directivas a mi archivo .htaccess, ya que no tengo la capacidad de editar las configuraciones de Apache en mi host compartido. Encontré excelentes herramientas para ajustar esta configuración en report-uri.io/home/tools .
Michael McGinnis
¿Hay alguna manera de resolver esto con Tomcat 7. He intentado agregar filtros y no funcionó.
Elshan
0

No se olvide del font-src, funciona igual que cualquier otro, pero si usa fuentes cargadas de otros orígenes, asegúrese de agregarlo a la metaetiqueta

Mikhail Andrianov
fuente