CSP : Content Security Policy (header)

Article publié, le et modifié le
11 minute(s) de lecture

Cet article contient 2137 mots.
Source brute de l'article : MD

Définition

CSP est une politique de sécurité relative au contenu que votre site “distribue” vers l’utilisateur final, quelque soit son client web. Cette entête HTTP permet de contrôler très finement l’accès aux ressources de votre site et des ressources partagées par d’autres à-partir de votre site.

Cette politique de sécurité impose que le développement des codes CSS } et JS soit propre, c’est-à-dire “embarqué” par les balises HTML adéquates pour charger du code source correspondant, et non pas embarqués dans le code source HTML. On parle de code inline ; c’est cela qu’il faut éviter…

Le bénéfice de sécurité est vraiment important, mais regorge de difficultés conséquentes, car il est vraiment nécessaire de comprendre les impacts des différentes directives qui vont plus ou moins empêcher l’accès aux ressources !

Il faut aussi assimiler qu’avec une seule entête HTTP, il est possible d’avoir un éventail d’interactions qui ne sont pas anodines.

Il y a actuellement deux normes :

  • CSP 1 est normalement supportée par l’ensemble des navigateurs connus, sauf Opera Mini
  • CSP 2 est généralement bien supportée par l’ensemble des navigateurs, seul Firefox a un support partiel, et IE et Opera Mini n’ont pas de support du tout ! Si vous avez un problème d’affichage, mettez-à-jour votre client web - sauf pour les deux derniers suscités
  • une troisième version est en cours de travail auprès du W3C. Officiellement, aucun support pour aucun navigateur web !
Attention

Modes

Il y a deux modes possibles, et il est vraiment conseillé de commencer avec le premier, histoire de réaliser les tenants et aboutissants :

  • Content-Security-Policy-Report-Only : ce mode est à considérer comme un mode de test, qui n’a pas d’impact sur votre site web, mais permet de tester les différentes directives
  • Content-Security-Policy : est le mode d’application des directives

Directives

Il a vraiment beaucoup de directives, d’autant que selon la version de la politique CSP, certaines sont déclarées obsolètes…

La première directive à mettre-en-place est la directive par défaut :

  • default-src : est la directive qui définit par défaut le comportement de l’entête CSP. - norme CSP 1 -
    Attention, seules certaines directives sont assujetties à cette directive par défaut : child-src, connect-src, font-src, img-src, manifest-src, media-src, object-src, script-src, style-src et worker-src !

Voici les autres directives qui peuvent être mises-en-place :

  • base-uri : définit l’URI que le client web utilisera comme base de la page web affichée - norme CSP2 -
  • block-all-mixed-content : empêche que le client web (télé)charge du contenu sur le protocole HTTP alors que la page est consultée en mode HTTPS
  • child-src : définit les sources valides relatives aux contenus autorisés - norme CSP2 -
  • connect-src : définit quelles sources sont valides pour les connexions de type XMLHttpRequest, WebSocket, et assimilées. - norme CSP 1 -
  • disown-opener; : assure qu’une ressource ne puisse être ouverte lors de sa consultation - norme CSP3 -
  • font-src : directive ayant un impact sur les polices à afficher. - norme CSP 1 -
  • form-action : définit l’interaction avec l’élément HTML form. - norme CSP2 -
  • frame-ancestor : directive pour les ressources partagées par les frames embarquées - norme CSP2 - c’est l’équivalent de l’entête X-Frame-Options
  • frame-src : directive pour les ressources partagées par les frames embarquées. - norme CSP 1 - dépréciée en CSP2 - réintroduite dans CSP 3
  • img-src : directive ayant un impact sur les images à charger. - norme CSP 1 -
  • manifest-src : définit quel manifeste peut être appliquée à la ressource. - norme CSP3 -
  • media-src : directive pour les ressources audio, et vidéo. - norme CSP 1 -
  • navigate-to : directive pour contrôler les ressources autorisées à la navigation - norme CSP3 -
  • object-src : directive pour les ressources qui chargent des plugins, des applets et autres éléments embed. - norme CSP 1 -
  • plugin-types : directive qui définit le type des ressources qui peuvent être chargées. - norme CSP2 -
  • referrer : directive équivalent à l’entête Referrer - cette directive a ses propres mots-clés !
  • reflected-xss : directive pour filtrer les attaques de type XSS - équivalent de l’entête X-XSS-Protection - cette directive a ses propres mots-clés !
  • report-to : spécifie un jeton qui définit un groupe de rapports à envoyer. - norme CSP3 -
  • report-uri: : directive qui définit l’URL où reporter les violations de sécurité. - norme CSP 1 - dépréciée en CSP3 , au profit de report-to -
  • require-sri-for : directive qui oblige l’attribut SRI pour les scripts et autres styles. - cette directive a ses propres mots-clés !
  • sandbox : directive qui utilise une sandbox HTML pour protéger l’exécution des ressources. - cette directive a ses propres mots-clés ! - norme CSP 1 -
  • script-nonce : directive qui autorise l’exécution d’un script seulement s’il y a correspondance avec l’attribut nonce. cf : les explications liées au mot-clé nonce ci-dessous…
  • script-src : directive qui régit les scripts exécutables, tels que JS. - norme CSP 1 -
  • style-src : directive qui régit les feuilles de styles. - norme CSP 1 -
  • upgrade-insecure-requests : oblige toute requête faite en HTTP à basculer en HTTPS si une page est chargée en HTTPS.
  • worker-src : définit quelles URL peuvent être chargées en tant que Worker, Sharedworker ou ServiceWorker.

Il est très possible, du fait de l’évolution de la norme de cette entête que j’ai oublié la présentation de certaines directives… veuillez vérifier auprès du W3C.

Info

Notes

  • Du fait que la directive default-src n’a pas d’impact sur certaines directives, telles que frame-ancestor, form-action, si ces dernières ne sont pas spécifiées, alors l’émission de données correspondantes sera envoyée…
  • La directive block-all-mixed-content est évaluée après la directive upgrade-insecure-requests
  • La directive child-src remplace la directive frame-src
    • Si la directive child-src n’est pas définie, elle est influencée par default-src- c’est le cas de toutes les directives assujetties à cette dernière
    • Il est préférable de l’utiliser pour les scripts “dépendants” plutôt que l’usage de la directive script-src.
    • Si les directives frame-src, work-src ne sont pas spécifiées, la politique child-src s’applique.
  • La directive plugins-type n’accepte pas le caractère wildcard * ; il faut définir un type MIME : e.g : application/pdf !

==== Recommandations ===

  • La première des recommandations est : Il n’y a rien de pire de ne rien faire que de spécifier plusieurs fois la même directive… seule la première directive est prise-en-compte !
  • La deuxième est de démarrer avec la déclaration suivante : default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; ; et de voir comment cela réagit ! ;-)
  • Concernant la directive object-src, préférez l’usage du mot-clé none, sauf à avoir l’absolu nécessité d’exécuter des scripts Flash, ou Silverlight.
  • Concernant les directives block-all-mixed-content et upgrade-insecure-requests, il est recommandé d’activer ou l’une, ou l’autre, mais pas les deux !
  • Attention à l’usage de la déclaration suivante : script-src 'self' qui peut ne pas être sûre en présence de JSONP.
  • Idéalement, utiliser la directive report-uri qui postera du contenu JSON pour relever les violations de sécurité, par vos propres moyens, ou au-travers d’un service fourni par un tiers.

Mots-clés

Aux directives, il est possible d’appliquer un ou plusieurs mots-clés :

  • * : autorise toutes les ressources. Ce wilcard peut s’appliquer aussi dans l’écriture des schemes, des URL et des ports autorisés, tel que : *://*.domaine.xyz:// <= cet exemple signifie l’autorisation de toutes les ressources des différents sous-domaine, quelque soit le protocole utilisé, et sur n’importe quel port de connexion.
  • 'none' : refuse toutes les ressources - C’est la politique à préférer, en terme de sécurité absolue, sur la directive par défaut !
  • 'self' : autorise les ressources du domaine en cours ; ne gèrent pas les ressources de sous-domaines, s’ils existent… il faut les autoriser explicitement par l’ajout de l’URL correspondante ! - C’est la politique minimale à appliquer sur la directive par défaut.
  • 'strict-dynamic' : autorisera les scripts à charger leurs dépendances sans avoir à les autoriser spécifiquement - norme CSP3 -
  • 'unsafe-inline' : permet l’usage du code inline CSS ou JS.
  • 'unsafe-eval' : permet l’évaluation de tout…
  • 'unsafe-hashed-attributes' : autorisera les gestionnaires d’événements selon leur hash. - norme CSP3 -

Mots-clés relatifs à la gestion des données - dans chaque cas, il est strictement nécessaire de spécifier une URI :

  • blob: : autorise l’usage de binaires
  • data: : autorise l’usage des données relatives à certaines directives utilisées, telles que les directives script-src, styles-src,… cela peut être des images encodées en base64
  • filesystem: : autorise l’usage de ressources depuis le système de fichiers.
  • https: : oblige les ressources à être chargées absolument par le biais du protocole HTTPS.
  • mediastream: : autorise le chargement de streaming de médias audio, vidéo,…
  • wss: : autorise le chargement des websockets !

Mots-clés relatifs à la directive referrer :

  • origin : le client web envoie toujours l’origine de l’entête vers le même site
  • origin-when-cross-origin : le client web enverra l’origine de l’entête uniquement vers le même site même lorsque les origines sont croisées.
  • no-referrer : n’envoie pas l’entête
  • no-referrer-when-downgrade : n’envoie pas l’entête quand le client navigue depuis HTTPS vers HTTP
  • same-origin : envoie l’entête si seulement vers le même site
  • unsafe-url : envoie toujours l’entête vers tous.

Mots-clés relatifs à la directive reflected-xss :

  • allow : désactive toute protection contre les attaques XSS.
  • block : bloque le chargement des ressources si une attaque XSS est détectée
  • filter : filtre la charge XSS avant son exécution

Mots-clés relatifs à la directive require-sri-for :

  • script : oblige l’attribut integrity pour les scripts
  • style : oblige l’attribut integrity pour les styles
  • script, style : oblige l’attribut integrity pour les scripts et les styles

Mots-clés relatifs à la directive sandbox :

  • sandbox : active la protection avec toutes les restrictions en place. Aucune des autres valeurs ne doit être spécifiée afin que toutes les restrictions soient respectées !
  • allow-forms : permet une page à soumettre un formulaire
  • allow-pointer-lock : évalue la gestion du pointeur de souris.
  • allow-modals : permet les interactions avec le client web.
  • allow-popups : autorise l’ouverture de popups
  • allow-same-origin : permet à une page d’accéder à du contenu depuis le même site
  • allow-scripts : permet à une page d’exécuter ses scripts
  • allow-top-navigation : permet à une page de ???

Il existe deux mots-clés très spécifiques :

  • hash : il permet d’autoriser un script, ou un style en particulier selon le hash définit… le hachage est calculé selon un des trois algorithmes SHA-2 (sha256, sha384 - politique minimale recommandée, sha512), encodé en base64. e.g. : style-src 'sha256-HashDigestHere='
  • nonce : acronyme de Number used Once - Numéro utilisé une seule fois - ; il permet d’autoriser un script inline selon la valeur dynamique aléatoire autorisé.

Il est très possible, du fait de l’évolution de la norme de cette entête que j’ai oublié la présentation de certains mots-clés… veuillez vérifier auprès du W3C.

Recommandations

  • Il est recommandé d’appliquer le mot-clé https: sur la directive par défaut, tel que : default-src: https: . Cela désactive le code inline et oblige toute connexion en mode HTTPS seulement.
  • Il est clairement recommandé d’éviter l’usage du mot-clé unsafe-inline !
    Malheureusement, parfois certains scripts “embarqués” ou styles extérieurs nécessitent des données et autres codes qu’il est difficile de gérer finement ; c’est la solution du “moins pire”
  • Il est assurément recommandé de ne pas utiliser le mot-clé unsafe-eval !
  • Attention à l’usage du mot-clé data: : par ce biais, il peut remonter des contenus “dérivés” inhérents aux directives object-src, script-src,…
  • L’attribut nonce doit être unique, re-généré à chaque fois, et bien entendu doit être non trivial et non devinable !`

Risques

Les risques possibles sont liés à :

  • Des erreurs de configuration, dues à des incompréhensions - d’où l’intérêt de tester avant l’application ;)
  • l’application de politique trop permissive, tel que l’usage des mots-clés unsafe-*
  • Utiliser le mot-clé unsafe-inline est l’équivalent de ne pas avoir de politique de sécurité ; quant à utiliser le mot-clé unsafe-eval est assurément l’équivalent d’un trou béant dans votre site web où vous permettez à tout le monde de faire n’importe quoi… <= vous, voilà, prévenus !!!
    oui, j’exagère peut-être un peu… mais le risque est réel, et sérieux.

Examples

Content-Security-Policy: default-src https:

Il est possible de la définir par le biais de l’élément HTML meta, tel que :

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

nginx

add_header Content-Security-Policy "default-src 'self';" always;

relayd

Et, oui, malheureusement, httpd ne peut pas gérer les entêtes, ce sera son binôme relayd(8) que l’on utilisera !

match response header set "Content-Security-Policy" value "default-src 'self' data: 'unsafe-inline'; base-uri \*://domain.tld ; form-action 'self'; frame-ancestors 'none'; referrer no-referrer; reflected-xss block; sandbox allow-same-origin ; script-src 'self' cdnjs.cloudflare.com netdna.bootstrapcdn.com ;"

Documentations

Autres sites intéressants