strict-dynamic expliqué, abandonnez les allowlists de hosts pour une CSP stricte
CentralCSP Team ·
Dernière mise à jour:
Les allowlists de hosts dans une politique de sécurité du contenu (CSP) donnent un
sentiment de sécurité qui, le plus souvent, n'en est pas un. Vous listez les domaines
d'où viennent vos scripts, mais vous faites confiance à chaque fichier de chacun de ces
domaines, y compris ceux que vous n'y avez pas mis. Il suffit d'un CDN de confiance qui
sert aussi un fichier accessible à un attaquant, et l'allowlist est contournée. Le
mot-clé 'strict-dynamic' est la réponse moderne : au lieu de faire confiance à des
domaines, vous faites confiance à des scripts précis que vous marquez, et vous laissez
ces scripts se porter garants de ceux qu'ils chargent.
Le problème que résout strict-dynamic
Prenez une politique comme script-src 'self' https://cdn.example.com. Elle fait
confiance à chaque script de ce CDN, et par extension à chaque script que ces scripts
chargent. Les chercheurs en sécurité ont montré à de nombreuses reprises que les grandes
allowlists sont contournables : un endpoint JSONP, une redirection ouverte ou une
bibliothèque obsolète hébergée sur un domaine de l'allowlist peuvent être détournés en
exécution de script arbitraire, que la politique autorise sans broncher. Plus vous
ajoutez de domaines pour que le site continue de fonctionner, plus la politique
s'affaiblit.
'strict-dynamic' retire le domaine de la décision de confiance. Le navigateur cesse de
demander « ce script vient-il d'un host autorisé » et commence à demander « ce script
a-t-il été cautionné », une question bien plus difficile à satisfaire pour un attaquant.
Comment ça marche
Vous marquez les scripts de confiance avec un
nonce ou un hash,
et vous ajoutez 'strict-dynamic' à script-src. Le navigateur fait confiance à ces
scripts marqués et propage cette confiance à tout script qu'ils créent au runtime, tout
en ignorant les host-sources et l'expression 'self' pour les scripts.
Content-Security-Policy:
script-src 'nonce-r4nd0m' 'strict-dynamic';
object-src 'none';
base-uri 'none'Le nonce est une nouvelle valeur aléatoire que votre serveur génère par réponse et place
à la fois dans le header et sur chaque balise <script> de confiance (voir comment configurer un nonce selon le framework). 'strict-dynamic' indique alors qu'un
script auquel le navigateur fait déjà confiance (parce qu'il portait le nonce) est
autorisé à charger d'autres scripts, qui héritent de cette confiance. Un loader de
confiance peut donc tirer les tiers dont il a besoin sans que vous énumériez le moindre
host.
La confiance part du script marqué par le nonce et se propage vers l'extérieur, tandis que les allowlists de hosts sont ignorées pour les scripts :
strict-dynamic comparé à un simple nonce
Un nonce seul ne fait confiance qu'aux balises exactes sur lesquelles vous l'avez posé.
Cela casse le schéma courant où un script de confiance en injecte dynamiquement un autre,
un loader d'analytics qui ajoute un tracker, ou un tag manager qui écrit d'autres balises
de script (voir GTM sous une CSP stricte avec Next.js). Sans
'strict-dynamic', ces scripts injectés n'ont pas de nonce et sont bloqués. Avec lui,
ils sont autorisés parce que le script qui les a créés était de confiance. Cette
propagation est précisément la raison d'ajouter le mot-clé en plus d'un nonce.
Ce qu'il ignore, et ce qui s'applique encore
Quand 'strict-dynamic' est présent, le navigateur ignore les host-sources, les sources
de schéma, 'self' et 'unsafe-inline' pour les scripts ; la confiance ne découle que
d'un nonce ou d'un hash. C'est pourquoi vous pouvez laisser une allowlist de hosts dans
la politique pour les anciens navigateurs sans affaiblir les navigateurs modernes, qui se
contentent de l'ignorer.
Conservez object-src 'none' et base-uri 'none' dans la politique quoi qu'il arrive.
'strict-dynamic' ne gouverne que les scripts, donc les plugins et une balise <base>
détournée ne sont pas couverts, et ces deux directives ferment des contournements que la
confiance des scripts ne couvre pas.
Support des navigateurs
'strict-dynamic' est largement supporté par les navigateurs actuels. Les anciens
navigateurs qui ne comprennent pas le mot-clé l'ignorent et retombent sur l'allowlist de
hosts, ce qui explique pourquoi vous pouvez déployer les deux : l'allowlist est un repli
pour les moteurs anciens, pas le contrôle principal. Présentez-la ainsi plutôt que comme
quelque chose à maintenir indéfiniment.
Voyez-le dans vos reports
Ne basculez pas une politique stricte à l'aveugle. Déployez-la d'abord en Report-Only et observez quels scripts seraient cassés, car un loader dynamique oublié peut faire tomber les analytics ou les paiements. CentralCSP collecte ces reports depuis le trafic réel, pour que vous confirmiez que la politique est sûre face à ce que les utilisateurs chargent réellement avant de l'appliquer.

Étapes suivantes
- Retirez d'abord les scripts inline : se débarrasser de unsafe-inline, et le mot-clé associé unsafe-eval.
- Voyez comment les directives de script se répartissent : script-src-elem vs script-src-attr.
- Notez une politique stricte avec le évaluateur CSP.
- Configurez le nonce dans votre stack : CSP nonce avec Next.js.
Déployez une CSP stricte en toute confiance.