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’orienter les internautes vers des sites sécurisés. Edge en fait autant, et Opera propose une extension dans cette optique.
Mais le https
et le certificat SSL qui va avec ne sont que l’un des outils mis à disposition pour sécuriser un site web. Et si vous n’allez pas plus loin, votre site ne sera pas sécurisé, loin s’en faut. Vous n’obtiendrez probablement pas un A+ en testant la sécurité de votre site avec des outils tels que Qualys de SSL Labs ou avec Security Headers.
Ces deux outils ne se font pas concurrence, ils se complètent. Autant Qualys va se focaliser sur le certificat, les protocoles (HSTS, OCSP Stapling, TLS…), autant Security Headers ne va s’occuper que des en-têtes de votre site web pour déterminer à 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 contribue à réduire les attaques XSS et les injections de contenu. C’est vous qui décidez des ressources – internes et externes – que le navigateur a la permission de charger 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 :
Mais attention ! Ce n’est qu’un outil, c’est à vous que revient la décision de charger ou de ne pas charger, d’exécuter ou de ne pas exécuter une ressource. Et donc, régulièrement, en amont, de vérifier qu’il n’y ait pas de code malicieux bien caché dans une extension, un service en ligne ou dans un thème… Opération fastidieuse certes, mais indispensable. Parce que même si vos ressources personnelles sont clean, un script hébergé ailleurs peut toujours être infecté, à dessein ou accidentellement.
Ceci dit, je ne vous conseille pas de réaliser cette opération manuellement, mais plutôt en utilisant un outil tel que Virus Total. Nouvelle extension, nouveau thème ? Ayez le réflexe Virus Total (associé à une extension de sécurité telle que Wordfence) et dormez sur vos deux oreilles !
Le contenu de l’en-tête Content Security Policy
Que doit contenir cet en-tête ? A minima, de quoi charger 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/
principalement). Avec la directive default-src
, c’est le mot clé base-uri
qui s’en chargera 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éclaration, nous avons une police de sécurité a minima, mais qui ne suffira pas pour la grande majorité des sites web.
Heureusement, on peut aller plus loin, et définir une ou des sources autorisées pour chaque type de contenu. Pour les scripts, les styles, les formulaires, les images, les médias (Youtube, Vimeo…), les iframes, les polices de caractères, la connection à des API, etc.
Par contre, de base, vous ne pourrez pas accepter l’exécution de scripts inclus dans la page, à moins de créer une faille dans la sécurité. Pour autoriser un tel script, il vous faudra soit leur attribuer une nonce, soit calculer leur empreinte, encodée via le protocole sha. Vous ne pourrez pas non plus exécuter le code lié à un événement tel que onclick
ou onload
sans lui attribuer son empreinte sha dans l’en-tête.
Vous trouverez des exemples simples ainsi qu’une une liste exhaustive des directives, avec leur compatibilité par navigateur (tout n’est pas parfait en ce bas monde) sur le site Mozilla.
Nonces et SHA
WordPress utilise les nonces dans d’autres circonstances que celles qui nous intéressent, pour renforcer la sécurité des formulaires 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 caractères générés aléatoirement qui n’ont pas vocation à être réutilisés. C’est ce qui fait leur force, ils changent (ou devraient changer) à chaque chargement de la page. Mais – revers de la médaille – l’usage de nonces interdit une déclaration unique depuis votre serveur, à moins d’utiliser en permanence les mêmes nonces, ce qui en réduirait considérablement l’efficacité.
Enfin, un virtuose du code pourrait peut-être (sûrement ?) créer des règles pour générer en live les nonces en utilisant les ressources du serveur web, mais ce n’est pas à la portée du commun des mortels. Ceux qui peuvent configurer correctement un serveur web ne sont déjà pas légion…
La déclaration dans les balises se fait sous forme d’attribut : nonce="…"
, la déclaration 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’encryptage via sha256 est le plus souvent utilisé, notez que l’en-tête Content Security Policy autorise l’utilisation de sha384 et de sha512. Contrairement aux nonces, l’encodage sha est fixe : une chaîne de caractères donnera invariablement la même chaîne en sha (256/384/512).
C’est une sécurité dans le sens où il a fallu réaliser l’opération d’encodage avant de construire l’en-tête – et que vous êtes supposés avoir vérifié votre code avant de l’encoder. Lors de l’encodage, seul le contenu inclus entre les balises <script>
et </script>
, ou inclus entre les quotes doubles pour un événement doit être utilisé.
La déclaration dans l’en-tête comprend le préfixe sha256-
/ sha384-
/ sha512-
suivi de la chaîne cryptée encodé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 cherché dans le dépôt WordPress une extension 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, calculer le sha des scripts inclus et des événements, récupé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 à partager ensuite – comme pour l’extension stop XML-RPC Attacks – toujours en lien avec la sécurité d’ailleurs !
Que fait exactement cette extension ? 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énements en ligne (onclick
et onload
) et construit l’en-tête Content Security Policy pour chaque page, en fonction de son contenu.
Je l’ai testée sur un serveur Plesk (bundle Nginx / Apache), sur un serveur openlitespeed avec lscache activé… a priori tout fonctionne – pour le moment, mais je n’ai pas de vidéo embarquée, je ne communique 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 fonctionne. Seules les ressources déclarées et donc autorisées pourront être utilisées sur la page.
Mais comme je vous l’ai déjà dit plus haut dans l’article, cette sécurité ne vaut que si vous avez préalablement vérifié que vos scripts et styles n’incluent pas de code malicieux.
À venir dans l’extension CSP ANTS&ST
Je n’ai pas implémenté – loin s’en faut – toutes les fonctionnalités offertes par l’en-tête Content Security Policy. On peut même dire que je n’ai implémenté que le strict minimum pour une utilisation générique.
Dans un premier temps, je vais m’attacher à ne déclarer que ce qui doit réellement être déclaré – nul besoin par exemple d’assigner une nonce à un script externe à la page, hébergé sur le domaine ou sur un domaine de confiance.
Les prochaines directives que je mettrai en œuvre sont form-action
pour les formulaires, child-src
– ou media-src
, à voir laquelle est la plus pertinente – pour autoriser le contenu embarqué (Youtube, Vimeo, Twitter…). Et probablement font-src
, pour limiter l’usage de https://fonts.googleapis.com/
aux polices de caractères, de même que connect-src
pour les connections via XHR
, WebSockets
et EventSource
(pour les cartes Google Maps par exemple).
Je vais également revoir le code, afin de le simplifier et de factoriser tout ce qui peut l’être, pour en faciliter la lecture et la maintenance, et pour des temps d’exécution plus courts.
Une page d’options est en gestation et me parait indispensable, 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 effectuée ou pas, si l’on est sur un serveur Nginx, Apache, Openlitespeed, si autoptimize est activé, ou Lscache, avec quels réglages…
Mais avant, je préfère poursuivre l’implémentation de fonctionnalités essentielles pour avoir une idée plus exacte de ce que doit contenir 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 configuration de votre serveur web, dans l’interface idoine prévue par votre hébergeur, ou plus simplement, en installant et en activant l’extension CSP ANTS&ST.
Et si vous avez une question, une suggestion ou si vous voulez partager votre propre expérience, direction les commentaires !