script-src-elem contre script-src-attr, quelle directive CSP contrôle quoi
CentralCSP Team ·
Dernière mise à jour:
script-src-elem
régit les éléments <script>, externes et inline. script-src-attr
régit les attributs event handler inline comme onclick. Les deux sont des
découpages plus fins de script-src,
et les deux retombent sur elle. La plupart des sites ne les posent jamais
séparément, mais connaître ce découpage explique beaucoup de rapports de violation
déroutants de la politique de sécurité du contenu (CSP).
La chaîne de fallback
La CSP résout les contrôles de script du spécifique au général. Quand le navigateur
doit décider si un élément <script> peut s'exécuter, il cherche script-src-elem.
Quand il décide si un event handler inline peut s'exécuter, il cherche
script-src-attr. Si la directive spécifique est absente, la vérification retombe,
d'abord sur script-src, puis sur default-src,
en suivant la liste de fallback définie par CSP Level 3.
script-src-elem -> script-src -> default-src
script-src-attr -> script-src -> default-srcAinsi une politique avec seulement script-src contrôle quand même les deux,
éléments et handlers inline, parce que les deux retombent sur elle. Vous recourez
aux directives granulaires quand vous voulez traiter les deux cas différemment.
Une règle compte plus que le schéma ne le laisse penser : le fallback est un
remplacement, pas une fusion. Si votre politique contient script-src-elem, le
navigateur l'utilise seul pour les vérifications d'éléments et ignore complètement
script-src pour cette décision. Les sources listées dans script-src ne sont pas
reprises. Une politique comme
script-src 'self' cdn.example; script-src-elem 'nonce-abc' bloquera un script
venant de cdn.example s'il ne porte pas le nonce, parce que dès que
script-src-elem existe, elle devient le seul règlement pour les éléments.
script-src-elem contre script-src-attr
script-src-elem | script-src-attr | |
|---|---|---|
| Contrôle | éléments <script> (externes et inline) | attributs event handler inline (onclick, ...) |
| Retombe sur | script-src, puis default-src | script-src, puis default-src |
| Nonces | S'appliquent | Ne s'appliquent pas (aucun attribut pour en porter un) |
| Hashes | S'appliquent au contenu <script> inline | Exigent 'unsafe-hashes' pour matcher un handler |
URL javascript: | Régies ici (selon CSP Level 3) | Pas régies ici |
| Valeur stricte typique | 'nonce-...' 'strict-dynamic' | 'none' |
Le support navigateur n'est plus une raison de les éviter. Blink a livré les deux
directives des années avant les autres ; WebKit a suivi, et Gecko a été le dernier
moteur à les ajouter. Les trois prennent désormais en charge script-src-elem,
script-src-attr et 'unsafe-hashes', et les navigateurs plus anciens qui ne
reconnaissent pas les directives granulaires continuent simplement d'utiliser votre
script-src, donc le fallback sert aussi de filet de compatibilité.
script-src-elem, la directive des éléments
script-src-elem décide quels éléments <script> le navigateur exécutera. Cela
couvre à la fois les scripts externes (<script src="...">) et les blocs
<script> inline.
C'est là que s'appliquent les nonces et les hashes.
Une source 'nonce-...' correspond à un <script> qui porte le même attribut
nonce, et un hash 'sha256-...' correspond à un <script> inline dont le
contenu exact donne ce hash. 'strict-dynamic' vit aussi ici : il laisse un script
de confiance par nonce charger d'autres scripts, comme traité dans
ce que fait strict-dynamic.
Content-Security-Policy: script-src-elem 'nonce-r4nd0m' 'strict-dynamic'script-src-elem accepte les mêmes expressions de source que script-src. Un
détail qui surprend souvent est celui des URL javascript:. CSP Level 3 vérifie
une navigation javascript: contre script-src-elem, pas contre
script-src-attr, même si elle a des airs d'attribut quand elle se trouve dans un
href. Cette vérification est aussi le seul endroit où
'unsafe-hashes'
compte côté élément : un hash ne peut correspondre à une URL javascript: que si
ce mot-clé est présent.
script-src-attr, la directive des handlers inline
script-src-attr décide si les attributs event handler inline peuvent s'exécuter :
onclick, onerror, onload, et le reste. Elle ne touche pas du tout aux
éléments <script>.
Les nonces ne s'appliquent pas à un attribut (il n'y a nulle part où mettre le
nonce), donc le seul moyen d'autoriser un handler est 'unsafe-inline', ou un
hash du code du handler combiné à 'unsafe-hashes'. Le hash seul ne suffit pas :
faire correspondre un hash à un event handler ou à un attribut style exige le
mot-clé supplémentaire 'unsafe-hashes', qui rouvre la surface des handlers
inline. C'est pourquoi le correctif plus propre est de retirer les handlers inline
et de les câbler avec addEventListener, comme traité dans
pourquoi ne jamais utiliser unsafe-inline.
Il y a un second piège ici. 'unsafe-inline' est ignoré dès qu'un nonce ou un hash
apparaît dans la même liste de sources. Donc script-src 'nonce-abc' 'unsafe-inline'
n'autorise pas discrètement vos handlers onclick ; le nonce désactive le mot-clé
'unsafe-inline', et les handlers restent bloqués. Si vous devez réellement
autoriser des handlers à côté d'une politique à nonce, l'autorisation doit vivre
dans sa propre directive script-src-attr.
Content-Security-Policy: script-src-attr 'none'Un exemple concret
Prenez une page avec trois choses : un script externe, un bloc <script> inline,
et un bouton avec un handler onclick inline.
<script src="/app.js" nonce="r4nd0m"></script>
<script nonce="r4nd0m">init();</script>
<button onclick="save()">Save</button>Sous une seule directive, tout est jugé par script-src :
Content-Security-Policy: script-src 'nonce-r4nd0m'Les éléments <script> externe et inline s'exécutent parce qu'ils portent le
nonce. Le handler onclick est bloqué, parce qu'un nonce ne peut pas correspondre
à un attribut. Le rapport de violation nomme script-src-attr comme directive
effective, même si vous n'avez écrit que script-src, parce que c'est la directive
spécifique qui régit un handler inline.
Maintenant découpez les deux :
Content-Security-Policy:
script-src-elem 'nonce-r4nd0m' 'strict-dynamic';
script-src-attr 'none'Même résultat, mais désormais chaque surface rend compte contre sa propre
directive. Un <script> bloqué produit une violation avec script-src-elem comme
directive effective ; un handler bloqué en produit une avec script-src-attr. Le
découpage rend les rapports non ambigus sur la surface qui a échoué, ce qui est
utile quand vous resserrez une politique et voulez voir les handlers inline
séparément des éléments script.
Lire les rapports de violation
La directive granulaire est ce qui apparaît dans votre télémétrie, que vous l'ayez
posée ou non. CSP Level 3 impose au navigateur de rapporter la directive effective
de la vérification, donc une violation de handler inline dit toujours
script-src-attr. Dans un rapport csp-violation
de la Reporting API le champ est effectiveDirective ; le JSON legacy de
report-uri utilise effective-directive, plus violated-directive comme alias
historique. Le détail champ par champ est dans
ce que signifie chaque champ de rapport de violation CSP.
Chromium explicite aussi le fallback dans la console. Un handler bloqué sous une
politique script-src simple journalise un message se terminant par "Note that
'script-src-attr' was not explicitly set, so 'script-src' is used as a fallback."
Quand vous voyez script-src-attr dans un rapport, lisez-le comme "un attribut
event handler inline a été bloqué", puis décidez de corriger le markup ou de
l'autoriser en connaissance de cause.
Cette distinction est la raison pratique de collecter les rapports plutôt que de lire la
console. CentralCSP regroupe les rapports csp-violation entrants par effectiveDirective,
si bien que script-src-elem et script-src-attr occupent des lignes distinctes même
quand votre politique ne définit que script-src. Les éléments bloqués et les
gestionnaires inline bloqués appellent des correctifs différents, et les séparer est ce
qui vous dit si vous avez un problème de script tiers ou un problème de markup.

Recommandation
Restez simple. Déployez un script-src strict bâti sur un nonce plus
'strict-dynamic', et ajoutez script-src-attr 'none' pour supprimer purement et
simplement les event handlers inline. Cette seule directive supplémentaire retire
toute une surface d'injection et n'affecte pas vos éléments <script>, que le
nonce régit déjà. Recourez à script-src-elem uniquement quand vous avez
réellement besoin de règles différentes pour les scripts d'éléments et les handlers
inline ; pour la plupart des sites, la politique ci-dessous, la CSP stricte OWASP
plus script-src-attr 'none', suffit. Vérifiez la politique finale avec le
évaluateur CSP.
Content-Security-Policy:
script-src 'nonce-r4nd0m' 'strict-dynamic';
script-src-attr 'none';
object-src 'none';
base-uri 'none'Le même découpage existe pour les styles :
style-src-elem
couvre les éléments <style> et les liens de feuilles de style,
style-src-attr
couvre les attributs style inline, et les deux retombent sur style-src de la
même manière.
FAQ
Pourquoi mon rapport CSP dit-il script-src-attr alors que je ne l'ai jamais posée ?
Parce que le navigateur rapporte la directive qui régit la vérification, pas celle
que vous avez écrite. effectiveDirective: script-src-attr signifie qu'un attribut
event handler inline (onclick, onerror, ...) a été bloqué ; votre script-src
n'a été consulté que comme fallback. Corrigez le handler en le déplaçant vers
addEventListener, ou autorisez-le en connaissance de cause via script-src-attr.
Les extensions de navigateur qui injectent des handlers sont une autre source
fréquente de ce bruit.
Pourquoi mon nonce ne fonctionne-t-il pas pour les handlers onclick ?
Les nonces ne peuvent jamais autoriser un event handler inline. La spécification ne
consulte les nonces que pour les éléments <script> et <style>, et un attribut
n'a nulle part où porter un nonce. Ajouter 'unsafe-inline' à côté du nonce
n'aide pas non plus, parce qu'un nonce ou un hash dans la liste de sources fait
ignorer 'unsafe-inline'. Réécrivez le handler avec addEventListener, ou
autorisez le code exact avec script-src-attr 'unsafe-hashes' 'sha256-...'.
Quelle est la différence entre script-src et script-src-elem ?
script-src-elem est le sous-ensemble limité aux éléments : elle régit les
éléments <script> et rien d'autre, tandis que script-src couvre aussi les event
handlers inline et l'exécution de type eval. La
référence script-src-elem
donne le détail complet.
Dois-je poser script-src-elem ?
Non. Quand elle est absente, script-src couvre les éléments script, et
default-src les couvre si script-src est absente aussi. Posez-la uniquement
quand éléments et handlers ont besoin de règles différentes, et rappelez-vous que
la poser remplace script-src pour les vérifications d'éléments au lieu de
fusionner avec elle, donc elle doit lister toutes les sources dont vos scripts ont
besoin.
Que fait unsafe-hashes en CSP ?
'unsafe-hashes' est un mot-clé de CSP Level 3 qui permet aux sources hash de
correspondre aux event handlers inline, aux attributs style inline et aux
navigations javascript:, que les hashes simples ne matchent jamais. Il est plus
sûr que 'unsafe-inline' parce que seul le code haché exact peut s'exécuter, mais
plus faible que retirer les handlers, puisque le code haché est alors autorisé dans
n'importe quel handler de la page.
Lectures liées
- script-src-elem et script-src-attr, les références de directive.
- Pourquoi ne jamais utiliser unsafe-inline dans une CSP,
pour retirer les handlers inline et le compromis
'unsafe-hashes'. - Ce que fait strict-dynamic et quand l'utiliser
- Ce que signifie chaque champ de rapport de violation CSP
Sources
- W3C, Content Security Policy Level 3 (liste de fallback des directives, directive effective pour les vérifications inline, rapport de violation)
- W3C, CSP editor's draft (définition de
'unsafe-hashes') - Chromium Blink, csp_directive_list.cc
(mapping des types inline, condition
'unsafe-hashes', message console de fallback) - Chromium, csp_source_list.cc
(
'unsafe-inline'neutralisé par les nonces et les hashes) - MDN, script-src-elem
- MDN, script-src-attr
- MDN, script-src
- MDN, CSPViolationReportBody
- MDN browser-compat-data, Content-Security-Policy
- OWASP, Content Security Policy cheat sheet