Renforcer la sécurité de son site avec l'en-tête Content Security Policy

La sécurité de votre site n'est plus une option. Si le certificat SSL et les mises à jour régulières sont indispensables, les en-têtes HTTP le sont tout autant. Dont l'en-tête Content Security Policy.

Cet article prend 7 minutes à lire et comporte 1532 mots.

Depuis des années, Chrome et Firefox tentent d’orien­ter les inter­nautes vers des sites sécu­ri­sés. Edge en fait autant, et Opera propose une exten­sion dans cette optique.

Mais le https et le certi­fi­cat SSL qui va avec ne sont que l’un des outils mis à dispo­si­tion pour sécu­ri­ser un site web. Et si vous n’al­lez pas plus loin, votre site ne sera pas sécu­risé, loin s’en faut. Vous n’ob­tien­drez proba­ble­ment pas un A+ en testant la sécu­rité de votre site avec des outils tels que Qualys de SSL Labs ou avec Security Headers.

Ces deux outils ne se font pas concur­rence, ils se complètent. Autant Qualys va se foca­li­ser sur le certi­fi­cat, les proto­coles (HSTS, OCSP Stapling, TLS…), autant Security Headers ne va s’oc­cu­per que des en-têtes de votre site web pour déter­mi­ner à quel point votre site est sécurisé.

Et l’une de ces en-têtes, c’est… je vous la donne en mille – Content Security Policy. Bien, me direz-vous. Mais…

L’en-tête Content Security Policy expliquée

Quelle est l’utilité de l’en-tête Content Security Policy ?

Cette en-tête contri­bue à réduire les attaques XSS et les injec­tions de contenu. C’est vous qui déci­dez des ressources – internes et externes – que le navi­ga­teur a la permis­sion de char­ger et d’exécuter.

Les sites de Facebook, de Twitter ou du Nouvel Obs pour ne citer qu’eux utilisent l’en-tête Content Security Policy, avec des règles plus ou moins strictes.

Et voici ce qui se passe quand une des règles n’est pas suivie :

Renforcer la sécurité de son site avec l'en-tête Content Security Policy
Violation des règles de l’en-tête 

Mais atten­tion ! Ce n’est qu’un outil, c’est à vous que revient la déci­sion de char­ger ou de ne pas char­ger, d’exé­cu­ter ou de ne pas exécu­ter une ressource. Et donc, régu­liè­re­ment, en amont, de véri­fier qu’il n’y ait pas de code mali­cieux bien caché dans une exten­sion, un service en ligne ou dans un thème… Opération fasti­dieuse certes, mais indis­pen­sable. Parce que même si vos ressources person­nelles sont clean, un script hébergé ailleurs peut toujours être infecté, à dessein ou accidentellement.

Ceci dit, je ne vous conseille pas de réali­ser cette opéra­tion manuel­le­ment, mais plutôt en utili­sant un outil tel que Virus Total. Nouvelle exten­sion, nouveau thème ? Ayez le réflexe Virus Total (asso­cié à une exten­sion de sécu­rité telle que Wordfence) et dormez sur vos deux oreilles !

Le contenu de l’en-tête Content Security Policy

Que doit conte­nir cet en-tête ? A minima, de quoi char­ger scripts, styles et images avec le même nom de domaine (ou de sous-domaine). Pour un site dont l’url est https://mon-domaine.com/ par exemple, tout ce qui est hébergé dans les sous-dossiers (https://mon-domaine.com/wp-content/ prin­ci­pa­le­ment). Avec la direc­tive default-src, c’est le mot clé base-uri qui s’en char­gera si vous avez implé­menté la balise <base> sur votre site. Sinon, le mot clé 'self' (quotes incluses) s’en occupera.

Ce qui donne cette en-tête :

Content-Security-Policy: default-src base-uri 'self'

Avec cette décla­ra­tion, nous avons une police de sécu­rité a minima, mais qui ne suffira pas pour la grande majo­rité des sites web.

Heureusement, on peut aller plus loin, et défi­nir une ou des sources auto­ri­sées pour chaque type de contenu. Pour les scripts, les styles, les formu­laires, les images, les médias (Youtube, Vimeo…), les iframes, les polices de carac­tères, la connec­tion à des API, etc.

Par contre, de base, vous ne pour­rez pas accep­ter l’exé­cu­tion de scripts inclus dans la page, à moins de créer une faille dans la sécu­rité. Pour auto­ri­ser un tel script, il vous faudra soit leur attri­buer une nonce, soit calcu­ler leur empreinte, enco­dée via le proto­cole sha. Vous ne pour­rez pas non plus exécu­ter le code lié à un événe­ment tel que onclick ou onload sans lui attri­buer son empreinte sha dans l’en-tête.

Vous trou­ve­rez des exemples simples ainsi qu’une une liste exhaus­tive des direc­tives, avec leur compa­ti­bi­lité par navi­ga­teur (tout n’est pas parfait en ce bas monde) sur le site Mozilla.

Nonces et SHA

WordPress utilise les nonces dans d’autres circons­tances que celles qui nous inté­ressent, pour renfor­cer la sécu­rité des formu­laires par exemple. Le nonce est en fait un jeton à usage unique, détruit après avoir été utilisé.

Les nonces sont des chaînes de carac­tères géné­rés aléa­toi­re­ment qui n’ont pas voca­tion à être réuti­li­sés. C’est ce qui fait leur force, ils changent (ou devraient chan­ger) à chaque char­ge­ment de la page. Mais – revers de la médaille – l’usage de nonces inter­dit une décla­ra­tion unique depuis votre serveur, à moins d’uti­li­ser en perma­nence les mêmes nonces, ce qui en rédui­rait consi­dé­ra­ble­ment l’efficacité.

Enfin, un virtuose du code pour­rait peut-être (sûre­ment ?) créer des règles pour géné­rer en live les nonces en utili­sant les ressources du serveur web, mais ce n’est pas à la portée du commun des mortels. Ceux qui peuvent confi­gu­rer correc­te­ment un serveur web ne sont déjà pas légion…

La décla­ra­tion dans les balises se fait sous forme d’at­tri­but : nonce="…", la décla­ra­tion dans l’en-tête comprend le préfixe nonce- suivi du nonce lui-même, le tout entre quotes simples (exemple : 'nonce-ca506d8715').

Même si l’en­cryp­tage via sha256 est le plus souvent utilisé, notez que l’en-tête Content Security Policy auto­rise l’uti­li­sa­tion de sha384 et de sha512. Contrairement aux nonces, l’en­co­dage sha est fixe : une chaîne de carac­tères donnera inva­ria­ble­ment la même chaîne en sha (256/384/512).

C’est une sécu­rité dans le sens où il a fallu réali­ser l’opé­ra­tion d’en­co­dage avant de construire l’en-tête – et que vous êtes suppo­sés avoir véri­fié votre code avant de l’en­co­der. Lors de l’en­co­dage, seul le contenu inclus entre les balises <script> et </script>, ou inclus entre les quotes doubles pour un événe­ment doit être utilisé.

La décla­ra­tion dans l’en-tête comprend le préfixe sha256- / sha384- / sha512- suivi de la chaîne cryp­tée enco­dée en base 64, le tout entre quotes simples. Un exemple : 'sha256-Aajrk2aqPW2es8Zhh7RGO98KAFtogitkC5mSBKgzFd0='.

Une extension pour gérer l’en-tête Content Security Policy

J’ai cher­ché dans le dépôt WordPress une exten­sion gérant cette en-tête, mais en vain. Il en existe bien sûr, mais elles ne répondent pas à mon besoin (insé­rer les nonces à la volée, calcu­ler le sha des scripts inclus et des événe­ments, récu­pé­rer les sources externes sûres, construire l’en-tête…) – alors j’en ai créé une 😉 et je l’ai nommée CSP ANTS&ST pour Content Security Policy – Add Nonces To Script & Style Tags.

Oui je sais, c’est une manie chez moi, quand je ne trouve pas, j’ai tendance à créer pour mes besoins… et à parta­ger ensuite – comme pour l’ex­ten­sion stop XML-RPC Attacks – toujours en lien avec la sécu­rité d’ailleurs !

Que fait exac­te­ment cette exten­sion ? Elle scanne votre page (enfin, son contenu), insère les nonces dans les balises script et style, calcule le SHA256 (encodé en base64) des événe­ments en ligne (onclick et onload) et construit l’en-tête Content Security Policy pour chaque page, en fonc­tion de son contenu.

Je l’ai testée sur un serveur Plesk (bundle Nginx / Apache), sur un serveur open­li­tes­peed avec lscache activé… a priori tout fonc­tionne – pour le moment, mais je n’ai pas de vidéo embar­quée, je ne commu­nique pas non plus avec d’autres serveurs via XHR ou quelque autre webservice.

Voici un exemple d’en-tête produit par l’extension :

content-security-policy: base-uri 'self' https://secure.gravatar.com/avatar/ https://fonts.googleapis.com/ data:; object-src 'none'; script-src https: 'nonce-ca506d8715' 'nonce-ec261423d8' 'nonce-50394a2304' 'unsafe-hashes' 'sha256-Aajrk2aqPW2es8Zhh7RGO98KAFtogitkC5mSBKgzFd0=' 'strict-dynamic'

C’est basique, mais ça fonc­tionne. Seules les ressources décla­rées et donc auto­ri­sées pour­ront être utili­sées sur la page.

Mais comme je vous l’ai déjà dit plus haut dans l’ar­ticle, cette sécu­rité ne vaut que si vous avez préa­la­ble­ment véri­fié que vos scripts et styles n’in­cluent pas de code mali­cieux.

À venir dans l’extension CSP ANTS&ST

Je n’ai pas implé­menté – loin s’en faut – toutes les fonc­tion­na­li­tés offertes par l’en-tête Content Security Policy. On peut même dire que je n’ai implé­menté que le strict mini­mum pour une utili­sa­tion générique.

Dans un premier temps, je vais m’at­ta­cher à ne décla­rer que ce qui doit réel­le­ment être déclaré – nul besoin par exemple d’as­si­gner une nonce à un script externe à la page, hébergé sur le domaine ou sur un domaine de confiance.

Les prochaines direc­tives que je mettrai en œuvre sont form-action pour les formu­laires, child-src – ou media-src, à voir laquelle est la plus perti­nente – pour auto­ri­ser le contenu embar­qué (Youtube, Vimeo, Twitter…). Et proba­ble­ment font-src, pour limi­ter l’usage de https://fonts.googleapis.com/ aux polices de carac­tères, de même que connect-src pour les connec­tions via XHR, WebSockets et EventSource (pour les cartes Google Maps par exemple).

Je vais égale­ment revoir le code, afin de le simpli­fier et de facto­ri­ser tout ce qui peut l’être, pour en faci­li­ter la lecture et la main­te­nance, et pour des temps d’exé­cu­tion plus courts.

Une page d’op­tions est en gesta­tion et me parait indis­pen­sable, pour éviter de perdre du temps à tester à chaque nouvelle page si telle ou telle ressource est présente, si telle ou telle action doit être effec­tuée ou pas, si l’on est sur un serveur Nginx, Apache, Openlitespeed, si autop­ti­mize est activé, ou Lscache, avec quels réglages… 

Mais avant, je préfère pour­suivre l’im­plé­men­ta­tion de fonc­tion­na­li­tés essen­tielles pour avoir une idée plus exacte de ce que doit conte­nir cette page d’options.

Et maintenant…

Que vous savez tout (ou presque) sur l’en-tête Content Security Policy, c’est à vous de jouer ! Implémentez l’en-tête dans votre .htaccess, dans le fichier de confi­gu­ra­tion de votre serveur web, dans l’in­ter­face idoine prévue par votre héber­geur, ou plus simple­ment, en instal­lant et en acti­vant l’ex­ten­sion CSP ANTS&ST.

Et si vous avez une ques­tion, une sugges­tion ou si vous voulez parta­ger votre propre expé­rience, direc­tion les commentaires !

Retour en haut
Les cookies que nous utilisons sont indispensables au bon fonctionnement de ce site. Il n'y a aucun pistage publicitaire et les données statistiques recueillies sont anonymisées.
J'ai compris