--- title: "CSP : Content Security Policy (header)" date: 2017-08-16T13:32:25+01:00 description: "Explications sur l'entête HTTP nommée CSP : Content Security Policy" draft: false lastmod: 2018-10-24T11:43:25+01:00 tags: ["HTTP", "Header", "CSP"] --- ## 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 {{< abbr HTTP "HyperText Transfer Protocol" >}} 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 {{< abbr CSS "Cascade StyleSheet" >}}} et {{< abbr JS "JavaScript" >}} soit propre, c'est-à-dire "embarqué" par les balises {{< abbr HTML "HyperText Markup Language" >}} 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](https://www.w3.org/TR/CSP1/) {{< color "dark-green" >}}1{{< /color >}} est normalement supportée par l'ensemble des navigateurs connus, sauf Opera Mini * [CSP](https://www.w3.org/TR/CSP2/) {{< color "green" >}}2{{< /color >}} 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](https://www.w3.org/TR/CSP3/) est en cours de travail auprès du W3C. Officiellement, aucun support pour aucun navigateur web ! {{% note warning %}} **ATTENTION** : Si le client web utilisé ne comprend pas une des directives CSP, il feint de l'ignorer, ni plus ni moins… Pour lui, elle n'existe pas ! {{% /note %}} ## 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 {{< color "dark-green" >}}CSP 1{{< /color >}} -
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 {{< color "green" >}}CSP2{{< /color >}} - * `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 {{< color "green" >}}CSP2{{< /color >}} - * `connect-src` : définit quelles sources sont valides pour les connexions de type XMLHttpRequest, WebSocket, et assimilées. - norme {{< color "dark-green" >}}CSP 1{{< /color >}} - * `disown-opener;` : assure qu'une ressource ne puisse être ouverte lors de sa consultation - norme {{< color "dark-red" >}}CSP3{{< /color >}} - * `font-src` : directive ayant un impact sur les polices à afficher. - norme {{< color "dark-green" >}}CSP 1{{< /color >}} - * `form-action` : définit l'interaction avec l'élément HTML form. - norme {{< color "green" >}}CSP2{{< /color >}} - * `frame-ancestor` : directive pour les ressources partagées par les frames embarquées - norme {{< color "green" >}}CSP2{{< /color >}} - *c'est l'équivalent de l'entête [X-Frame-Options](web:http:x-frame-options)*… * `frame-src` : directive pour les ressources partagées par les frames embarquées. - norme {{< color "dark-green" >}}CSP 1{{< /color >}} - {{< color "orange" >}}dépréciée{{< /color >}} en {{< color "green" >}}CSP2{{< /color >}} - *réintroduite dans {{< color "dark-red" >}}CSP 3{{< /color >}}* * `img-src` : directive ayant un impact sur les images à charger. - norme {{< color "dark-green" >}}CSP 1{{< /color >}} - * `manifest-src` : définit quel manifeste peut être appliquée à la ressource. - norme {{< color "dark-red" >}}CSP3{{< /color >}} - * `media-src` : directive pour les ressources audio, et vidéo. - norme {{< color "dark-green" >}}CSP 1{{< /color >}} - * `navigate-to` : directive pour contrôler les ressources autorisées à la navigation - norme {{< color "dark-red" >}}CSP3{{< /color >}} - * `object-src` : directive pour les ressources qui chargent des plugins, des applets et autres éléments embed. - norme {{< color "dark-green" >}}CSP 1{{< /color >}} - * `plugin-types` : directive qui définit le type des ressources qui peuvent être chargées. - norme {{< color "green" >}}CSP2{{< /color >}} - * `referrer` : directive *équivalent à l'entête [Referrer](web:http: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](web:http:x-xss-protections)* - cette directive a ses propres mots-clés ! * `report-to` : spécifie un jeton qui définit un groupe de rapports à envoyer. - norme {{< color "dark-red" >}}CSP3{{< /color >}} - * `report-uri:` : directive qui définit l'URL où reporter les violations de sécurité. - norme {{< color "dark-green" >}}CSP 1{{< /color >}} - *dépréciée en {{< color "dark-red" >}}CSP3{{< /color >}}, au profit de `report-to`* - * `require-sri-for` : directive qui oblige l'attribut {{< inside "web:http:sri" 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 {{< color "dark-green" >}}CSP 1{{< /color >}} - * `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 {{< color "dark-green" >}}CSP 1{{< /color >}} - * `style-src` : directive qui régit les feuilles de styles. - norme {{< color "dark-green" >}}CSP 1{{< /color >}} - * `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. {{< note info >}} Je ne détaillerai pas plus les différentes directives… pour cela, veuillez lire les documentations sur lesquelles j'attire votre attention dans la section ad hoc, et les référentiels W3C. {{< /note >}} ### 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 {{< color "dark-red" >}}CSP3{{< /color >}} - * `'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 {{< color "dark-red" >}}CSP3{{< /color >}} - ------------------------------------------------------------------------ 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 : `` ### nginx `add_header Content-Security-Policy "default-src 'self';" always;` ### relayd Et, oui, malheureusement, {{< tag httpd >}} ne peut pas gérer les entêtes, ce sera son binôme {{< man 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 * https://scotthelme.co.uk/csp-cheat-sheet/ * https://content-security-policy.com/ * https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP * https://www.owasp.org/index.php/Content_Security_Policy * https://openweb.eu.org/articles/content-security-policy ### Autres sites intéressants * https://report-uri.io * Support actuel : [http://caniuse.com/#search=csp](http://caniuse.com/#search=csp) ------------------------------------------------------------------------