web-dev-qa-db-fra.com

Comment fonctionne la politique de sécurité du contenu?

Je reçois beaucoup d'erreurs dans la console du développeur:

Refusé d'évaluer une chaîne

Refusé d'exécuter un script en ligne car il enfreint la directive suivante relative à la politique de sécurité du contenu

Refusé de charger le script

Refusé de charger la feuille de style

Qu'est-ce que tout cela signifie? Comment fonctionne la politique de sécurité du contenu? Comment utiliser l'en-tête HTTP Content-Security-Policy?

Plus précisément, comment ...

  1. ... autoriser plusieurs sources?
  2. ... utiliser des directives différentes?
  3. ... utiliser plusieurs directives?
  4. ... gérer les ports?
  5. ... gérer différents protocoles?
  6. ... autoriser le protocole file://?
  7. ... utiliser des styles, des scripts et des balises inline <style> et <script>?
  8. ... permet eval()?

Et enfin:

  1. Que signifie exactement 'self'?
204
Schlaus

La méta-balise Content-Security-Policy vous permet de réduire le risque d'attaques en XSS en vous permettant de définir l'emplacement de chargement des ressources, empêchant ainsi les navigateurs de charger des données à partir d'autres emplacements. Cela rend plus difficile pour un attaquant d'injecter du code malveillant dans votre site.

Je me suis cogné la tête contre un mur de briques pour essayer de comprendre pourquoi les erreurs de CSP m'attiraient les unes après les autres, et il ne semblait pas y avoir d'instructions claires et concises expliquant comment cela fonctionnait. Voici donc ma tentative d'explication de quelques points de CSP, en mettant l'accent sur les problèmes que je trouvais difficile à résoudre.

Par souci de concision, je n’écrirai pas l’étiquette complète dans chaque échantillon. Au lieu de cela, je ne montrerai que la propriété content, ainsi un exemple indiquant content="default-src 'self'" signifie:

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

1. Comment autoriser plusieurs sources?

Vous pouvez simplement lister vos sources après une directive sous forme de liste séparée par des espaces:

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

Notez qu'il n'y a pas de guillemets autour des paramètres autres que ceux spéciaux, comme 'self'. De plus, il n'y a pas de deux-points (:) après la directive. Juste la directive, puis une liste de paramètres séparés par des espaces.

Tout ce qui se situe en dessous des paramètres spécifiés est implicitement autorisé. Cela signifie que dans l'exemple ci-dessus, ces sources seraient valides:

https://example.com/js/file.js
https://example.com/js/subdir/anotherfile.js

Ceux-ci, cependant, ne seraient pas valables:

http://example.com/js/file.js
^^^^ wrong protocol

https://example.com/file.js
                   ^^ above the specified path

2. Comment utiliser différentes directives, que font-elles chacune?

Les directives les plus courantes sont:

  • default-src la politique par défaut pour le chargement de javascript, d'images, de CSS, de polices, de AJAX requêtes, etc.
  • script-src définit les sources valides pour les fichiers javascript
  • style-src définit les sources valides pour les fichiers CSS
  • img-src définit les sources valides pour les images
  • connect-src définit les cibles valides pour XMLHttpRequest (AJAX), WebSockets ou EventSource. Si une tentative de connexion à un hôte qui n'est pas autorisé ici, le navigateur émule une erreur 400.

Il y en a d'autres, mais ce sont ceux dont vous aurez le plus besoin.

3. Comment utiliser plusieurs directives?

Vous définissez toutes vos directives dans une méta-balise en les terminant par un point-virgule (;):

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

4. Comment gérer les ports?

Tout sauf les ports par défaut doit être autorisé explicitement en ajoutant le numéro de port ou un astérisque après le domaine autorisé:

content="default-src 'self' https://ajax.googleapis.com http://example.com:123/free/stuff/"

Ce qui précède entraînerait:

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

Comme je l'ai mentionné, vous pouvez également utiliser un astérisque pour autoriser explicitement tous les ports:

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

5. Comment gérer différents protocoles?

Par défaut, seuls les protocoles standard sont autorisés. Par exemple, pour autoriser WebSockets ws://, vous devrez l’autoriser explicitement:

content="default-src 'self'; connect-src ws:; style-src 'self'"
                                         ^^^ web sockets are now allowed on all domains and ports

6. Comment autoriser le protocole de fichier file://?

Si vous essayez de le définir comme tel, cela ne fonctionnera pas. À la place, vous l'autoriserez avec le paramètre filesystem:

content="default-src filesystem"

7. Comment utiliser les scripts en ligne et les définitions de style?

Sauf autorisation expresse, vous ne pouvez pas utiliser de définitions de style inline, de code dans les balises <script> ou dans les propriétés de balises telles que onclick. Vous leur permettez comme ça:

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

Vous devez également autoriser explicitement les images en ligne codées en base64:

content="img-src data:"

8. Comment autoriser eval()?

Je suis sûr que beaucoup de gens diraient que non, puisque "eval is evil" est la cause la plus probable de la fin du monde. Ces gens auraient tort. Bien sûr, vous pouvez percer des failles majeures dans la sécurité de votre site avec eval, mais ses cas d'utilisation sont parfaitement valables. Vous devez juste être intelligent pour l'utiliser. Vous le permettez comme ça:

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

9. Qu'est-ce que 'self' signifie exactement?

Vous pouvez prendre le terme 'self' pour désigner l’hôte local, le système de fichiers local ou tout autre élément du même hôte. Cela ne signifie aucun de ceux-là. Cela signifie que les sources ont le même schéma (protocole), le même hôte et le même port que le fichier dans lequel la stratégie de contenu est définie. Vous gérez votre site via HTTP? Pas de https pour vous alors, à moins que vous ne le définissiez explicitement.

J'ai utilisé 'self' dans la plupart des exemples, car il est généralement logique de l'inclure, mais cela n'est en aucun cas obligatoire. Laissez-le si vous n'en avez pas besoin.

Mais attendez une minute! Ne puis-je pas simplement utiliser content="default-src *" et en finir?

Non. Outre les failles de sécurité évidentes, cela ne fonctionnerait pas comme prévu. Même si certains documents affirme que tout est permis, ce n'est pas vrai. Cela ne permet pas l'inline ou les évaluations, donc pour vraiment rendre votre site plus vulnérable, vous utiliseriez ceci:

content="default-src * 'unsafe-inline' 'unsafe-eval'"

... mais je crois que vous ne le ferez pas.

Lectures supplémentaires:

http://content-security-policy.com

http://en.wikipedia.org/wiki/Content_Security_Policy

471
Schlaus

Apache2 MOD_HEADERS

Vous pouvez également activer Apache2 mod_headers. Sur Fedora, il est déjà activé par défaut. Si vous utilisez Ubuntu/Debian, activez-le comme suit:

# First enable headers module for Apache2, 
# then restart the Apache2 service   
a2enmod headers
Apache2 -k graceful

Sur Ubuntu/Debian, vous pouvez configurer les en-têtes du fichier /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;"

Remarque: il s'agit de la partie inférieure du fichier. Seules les trois dernières entrées sont des paramètres CSP.

Le premier paramètre est la directive, le second les sources à afficher en liste blanche. J'ai ajouté Google Analytics et un serveur de publicité, que vous pourriez avoir. De plus, j’ai trouvé que si vous avez des alias, par exemple www.example.com et example.com configurés dans Apache2, vous devez également les ajouter à la liste blanche.

Le code en ligne est considéré comme dangereux, vous devez l’éviter. Copiez tous les javascripts et css dans des fichiers séparés et ajoutez-les à la liste blanche.

Pendant que vous y êtes, vous pouvez consulter les autres paramètres d’en-tête et installer mod_security.

Lectures supplémentaires:

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

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

13
Erik Hendriks