CentralCSP
FonctionnalitésGénérateur CSP

Nonces et unsafe-inline

Comment le générateur CSP traite les scripts et styles inline, et comment remplacer unsafe-inline par un nonce dans votre politique sans casser vos pages.

Dernière mise à jour:

Le code inline est la raison la plus fréquente pour laquelle une politique de sécurité du contenu (CSP) reste faible. Cette page explique ce que fait le générateur CSP quand les navigateurs reportent des scripts ou des styles inline, et comment remplacer 'unsafe-inline' par un nonce.

Pourquoi unsafe-inline pose problème

Une attaque de cross-site scripting (XSS) injecte un bloc <script> ou un event handler comme onclick="…" dans votre page. 'unsafe-inline' autorise tous les scripts inline, donc le script injecté s'exécute exactement comme les vôtres. La politique ne protège alors presque plus contre l'attaque qu'elle est censée arrêter.

Un nonce est une valeur aléatoire que votre serveur génère pour chaque réponse. Il figure dans la politique et dans l'attribut nonce de chaque balise script que vous servez. Le navigateur n'exécute que les scripts inline qui le portent, et un attaquant ne peut pas le deviner.

Ce que fait le générateur avec le code inline

Quand les navigateurs reportent du code inline bloqué, le générateur suggère le mot-clé qui l'autoriserait :

  • Les scripts inline, les event handlers ou les styles inline donnent 'unsafe-inline' dans la directive qui les a bloqués.
  • eval() ou new Function() donne 'unsafe-eval'.

Les deux arrivent ajoutés, car vos pages exécutent ce code aujourd'hui et une politique qui le bloquerait les casserait. Les deux portent un signalement de risque, et leur panneau de détails affiche l'encadré Nécessaire aujourd’hui, à retirer ensuite avec la modification à faire dans votre code.

Quand la politique dont vous partez utilise déjà un nonce, le générateur procède autrement :

  • Le nonce revient sous la forme du placeholder 'nonce-{RANDOM}', puisque chaque réponse a besoin de sa propre valeur.
  • Un script-src ou un script-src-elem avec un nonce reçoit 'strict-dynamic', avec le libellé Recommandé. Les scripts chargés par vos scripts porteurs du nonce sont alors approuvés eux aussi, et leurs hôtes n'ont plus besoin d'être listés.
  • Un 'unsafe-inline' reporté dans le même type de directive arrive rejeté, avec l'encadré Rejetée car votre politique utilise un nonce. Les navigateurs ignorent 'unsafe-inline' partout où un nonce est présent, l'ajouter ne changerait donc rien.

Le générateur n'ajoute un nonce que si la politique dont vous partez en contient un. Il ne peut pas l'ajouter à votre place, car c'est votre serveur qui doit le générer.

Passer d'unsafe-inline à un nonce

Pour remplacer 'unsafe-inline' par un nonce :

  1. Sur votre serveur, générez une nouvelle valeur impossible à deviner pour chaque réponse, par exemple 16 octets aléatoires encodés en base64.
  2. Ajoutez nonce="<value>" à chaque balise <script> que servent vos pages, inline ou non. Avec 'strict-dynamic', une balise script sans le nonce ne se charge plus.
  3. Remplacez les event handlers inline, comme onclick="…", par des appels à addEventListener dans un fichier de script. Un event handler ne peut pas porter de nonce.
  4. Ajoutez 'nonce-<value>' au script-src de la politique report-only que vous envoyez déjà, et déployez-la.
  5. Attendez que les reports couvrent une période complète après votre déploiement, puis ouvrez le générateur CSP sur cette période.
  6. À l'étape Politique de départ, sélectionnez la politique en service. Elle porte la pastille Utilise des nonces.
  7. À l'étape Revue des sources, vérifiez que 'unsafe-inline' apparaît comme rejeté dans vos directives de script, et que les lignes reportées depuis des event handlers inline ont disparu.
  8. À l'étape Déployer, copiez les headers et déployez-les, en remplaçant {RANDOM} par la valeur de chaque réponse.

Vos pages n'exécutent plus que les scripts qui portent le nonce. Si une ligne reporte encore du code inline, sélectionnez-la et consultez Code en cause et Pages concernées pour trouver la balise ou l'event handler oublié.

Le header déployé et la balise script correspondante ressemblent à cet exemple :

Content-Security-Policy-Report-Only: script-src 'nonce-rAnd0m4bc123' 'strict-dynamic' 'report-sample' 'report-sha256'; object-src 'none'; base-uri 'self'; report-to centralcsp
<script nonce="rAnd0m4bc123" src="/js/app.js"></script>

Un nonce fixe ne protège rien. Si la valeur est la même à chaque réponse, un attaquant peut la lire et la réutiliser.

Styles inline

Les styles suivent les mêmes règles dans style-src. Pour retirer 'unsafe-inline' des styles, déplacez les blocs <style> dans une feuille de style ou donnez-leur le nonce, et remplacez les attributs style="…" par des classes CSS. Un attribut style ne peut pas porter de nonce. Les styles définis en JavaScript via element.style continuent de fonctionner.

Le risque des styles inline est plus faible que celui des scripts, vous pouvez donc garder 'unsafe-inline' dans style-src pendant que vous le retirez d'abord de vos directives de script.

Quand un nonce est impossible

Un site servi sous forme de fichiers statiques, sans code serveur exécuté à chaque réponse, ne peut pas générer de nonce. Dans ce cas :

  • Déplacez les scripts inline dans des fichiers servis par votre site, pour que votre propre origine les couvre.
  • Pour un script inline qui doit rester, autorisez plutôt son hash. Consultez Hashes et nonces.
  • Ne gardez 'unsafe-inline' que tant qu'une page en a encore besoin, et suivez-le grâce à son signalement de risque.

Seuls les anciens navigateurs lisent cette valeur

Quand votre politique contient script-src-elem ou script-src-attr, les navigateurs modernes lisent ces directives pour le code inline et ignorent script-src. Un 'unsafe-inline' laissé dans script-src ne concerne alors que les anciens navigateurs, et son panneau de détails affiche l'encadré Seuls les anciens navigateurs lisent cette valeur. Vérifiez plutôt le risque sur les lignes script-src-elem et script-src-attr. Il en va de même pour style-src-elem et style-src-attr.

Étapes suivantes

On this page