# script-src-elem contre script-src-attr, quelle directive CSP contrôle quoi (/fr/blog/script-src-elem-vs-script-src-attr)





[`script-src-elem`](/fr/docs/web-security/policies/content-security-policy/directives/script-src-elem)
régit les éléments `<script>`, externes et inline. [`script-src-attr`](/fr/docs/web-security/policies/content-security-policy/directives/script-src-attr)
régit les attributs event handler inline comme `onclick`. Les deux sont des
découpages plus fins de [`script-src`](/fr/docs/web-security/policies/content-security-policy/directives/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-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`](/fr/docs/web-security/policies/content-security-policy/directives/default-src),
en suivant la liste de fallback définie par CSP Level 3.

```text
script-src-elem  ->  script-src  ->  default-src
script-src-attr  ->  script-src  ->  default-src
```

Ainsi 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-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-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](/fr/docs/web-security/policies/content-security-policy/values/csp-hashes-nonce).
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](/fr/blog/strict-dynamic-csp).

```http
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'`](/fr/docs/web-security/policies/content-security-policy/values/csp-keywords)
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-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](/fr/blog/unsafe-inline-csp).

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`.

```http
Content-Security-Policy: script-src-attr 'none'
```

## Un exemple concret [#un-exemple-concret]

Prenez une page avec trois choses : un script externe, un bloc `<script>` inline,
et un bouton avec un handler `onclick` inline.

```html
<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` :

```http
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 :

```http
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 [#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](/fr/docs/web-security/reporting-api/reports/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](/fr/blog/csp-violation-report-fields).

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.

<img alt="La colonne Directive montrant script-src-elem et script-src-attr sur des lignes distinctes" src="__img0" width="1359" height="248" />

## Recommandation [#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](/tools/csp-evaluator).

```http
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`](/fr/docs/web-security/policies/content-security-policy/directives/style-src-elem)
couvre les éléments `<style>` et les liens de feuilles de style,
[`style-src-attr`](/fr/docs/web-security/policies/content-security-policy/directives/style-src-attr)
couvre les attributs `style` inline, et les deux retombent sur `style-src` de la
même manière.

## FAQ [#faq]

### Pourquoi mon rapport CSP dit-il script-src-attr alors que je ne l'ai jamais posée ? [#pourquoi-mon-rapport-csp-dit-il-script-src-attr-alors-que-je-ne-lai-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 ? [#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 ? [#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](/fr/docs/web-security/policies/content-security-policy/directives/script-src-elem)
donne le détail complet.

### Dois-je poser script-src-elem ? [#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 ? [#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 [#lectures-liées]

* [script-src-elem](/fr/docs/web-security/policies/content-security-policy/directives/script-src-elem)
  et [script-src-attr](/fr/docs/web-security/policies/content-security-policy/directives/script-src-attr),
  les références de directive.
* [Pourquoi ne jamais utiliser unsafe-inline dans une CSP](/fr/blog/unsafe-inline-csp),
  pour retirer les handlers inline et le compromis `'unsafe-hashes'`.
* [Ce que fait strict-dynamic et quand l'utiliser](/fr/blog/strict-dynamic-csp)
* [Ce que signifie chaque champ de rapport de violation CSP](/fr/blog/csp-violation-report-fields)

## Sources [#sources]

* [W3C, Content Security Policy Level 3](https://www.w3.org/TR/CSP3/) (liste de
  fallback des directives, directive effective pour les vérifications inline,
  rapport de violation)
* [W3C, CSP editor's draft](https://w3c.github.io/webappsec-csp/) (définition de
  `'unsafe-hashes'`)
* [Chromium Blink, csp\_directive\_list.cc](https://github.com/chromium/chromium/blob/main/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc)
  (mapping des types inline, condition `'unsafe-hashes'`, message console de
  fallback)
* [Chromium, csp\_source\_list.cc](https://github.com/chromium/chromium/blob/main/services/network/public/cpp/content_security_policy/csp_source_list.cc)
  (`'unsafe-inline'` neutralisé par les nonces et les hashes)
* [MDN, script-src-elem](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src-elem)
* [MDN, script-src-attr](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src-attr)
* [MDN, script-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/script-src)
* [MDN, CSPViolationReportBody](https://developer.mozilla.org/en-US/docs/Web/API/CSPViolationReportBody)
* [MDN browser-compat-data, Content-Security-Policy](https://github.com/mdn/browser-compat-data/blob/main/http/headers/Content-Security-Policy.json)
* [OWASP, Content Security Policy cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html)
