# CSP pour Google Analytics et Tag Manager avec un nonce (/fr/blog/csp-google-analytics-tag-manager)



Vous pouvez faire tourner [Google Analytics 4 (GA4)](https://developers.google.com/analytics) et [Google Tag Manager (GTM)](https://developers.google.com/tag-platform/tag-manager) sous une politique de sécurité du contenu (CSP) stricte sans l'affaiblir. Une CSP est un header de réponse HTTP qui indique au navigateur quels scripts et autres ressources une page peut charger et exécuter. La manière stricte d'autoriser GTM est un nonce sur le script d'amorçage GTM plus [`'strict-dynamic'`](/fr/docs/web-security/policies/content-security-policy/values/csp-keywords), pas une liste de domaines Google dans votre directive de script.

L'erreur courante est d'allowlister `googletagmanager.com` et `google-analytics.com` dans [`script-src`](/fr/docs/web-security/policies/content-security-policy/directives/script-src). Avec un nonce et `'strict-dynamic'` en place, le navigateur ignore entièrement les allowlists de hosts pour les scripts, donc ces entrées ne font rien. Cet article montre l'approche qui marche vraiment, où les domaines Google ont réellement leur place, et un exemple de header complet que vous pouvez adapter.

Les nonces vous sont nouveaux ? [Démarrer avec la Content Security Policy](/fr/blog/get-started-with-csp) explique ce qu'est un nonce et comment en générer un, et [comment construire une CSP solide](/fr/blog/how-to-build-a-strong-csp) couvre le workflow Report-Only d'abord que cet article suppose.

## Le point clé, ne listez pas les hosts Google dans script-src [#le-point-clé-ne-listez-pas-les-hosts-google-dans-script-src]

Quand `script-src` contient un nonce et `'strict-dynamic'`, le navigateur change sa façon de décider quels scripts peuvent s'exécuter. Il ignore les allowlists de hosts, [`'self'`](/fr/docs/web-security/policies/content-security-policy/values/csp-keywords), et les sources de schéma pour les scripts. Il ne fait confiance qu'aux scripts qui portent le nonce correspondant, et aux scripts que ces scripts de confiance chargent.

Donc `script-src https://www.googletagmanager.com https://www.google-analytics.com` ne sert à rien d'utile ici. Le navigateur l'ignore silencieusement. Ajouter ces hosts ne fait pas fonctionner GTM et ne le fait pas échouer, c'est juste du poids mort qui masque le vrai mécanisme.

Le mécanisme qui fonctionne : mettez le nonce sur le script inline d'amorçage GTM. Ce script est de confiance parce qu'il porte le nonce. [`'strict-dynamic'`](/fr/blog/strict-dynamic-csp) propage ensuite cette confiance à `gtm.js`, que GTM charge, puis à chaque tag que GTM injecte. Aucun domaine Google n'apparaît dans `script-src`. Cette propagation est aussi pourquoi GTM mérite d'être surveillé de près ; voyez [comment les attaquants détournent Google Tag Manager](/fr/blog/google-tag-manager-security-risk).

```mermaid
flowchart LR
  A["Nonce on inline<br/>GTM bootstrap"] -->|trusted by nonce| B["gtm.js"]
  B -->|strict-dynamic<br/>propagates trust| C["Tags GTM<br/>injects"]
```

## L'amorçage GTM avec nonce [#lamorçage-gtm-avec-nonce]

Le [snippet GTM officiel](https://developers.google.com/tag-platform/security/guides/csp) de Google propage déjà le nonce à la requête `gtm.js`. Utilisez cette version, où le nonce du script inline est lu et copié sur la balise de script injectée :

```html title="gtm-bootstrap.html"
<script nonce="{SERVER-GENERATED-NONCE}">(function(w,d,s,l,i){w[l]=w[l]||[];
w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});
var f=d.getElementsByTagName(s)[0], j=d.createElement(s),
dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;
var n=d.querySelector('[nonce]');
n&&j.setAttribute('nonce',n.nonce||n.getAttribute('nonce'));
f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');</script>
```

Deux détails rendent ceci compatible avec une CSP stricte :

* L'attribut `nonce="{SERVER-GENERATED-NONCE}"` est ce qui permet à `'strict-dynamic'` de faire confiance à ce script inline. Remplacez `{SERVER-GENERATED-NONCE}` par une valeur aléatoire base64 fraîche, par réponse, d'au moins 128 bits, la même que vous mettez dans le header CSP.
* Les lignes qui lisent `[nonce]` et appellent `j.setAttribute('nonce', ...)` copient le nonce sur le script `gtm.js` injecté. Avec `'strict-dynamic'`, cette propagation n'est pas strictement requise pour les scripts que GTM charge, mais elle maintient le nonce en circulation pour les tags qui le vérifient, donc gardez-la.

Générez le nonce sur le serveur et ne le réutilisez jamais d'une réponse à l'autre. Les bases de la génération de nonce sont dans [démarrer avec la Content Security Policy](/fr/blog/get-started-with-csp), donc cet article ne les répète pas. Sur Next.js, le nonce par requête vient du proxy et Next l'applique aux scripts qu'il rend ; voyez [comment mettre en place un nonce CSP dans Next.js](/fr/blog/csp-nonce-nextjs) pour ce câblage, puis mettez le même nonce sur l'amorçage GTM ci-dessous. Pour le pas à pas spécifique à GTM, voyez [GTM sous une CSP stricte dans Next.js](/fr/blog/gtm-csp-nextjs).

## Où les domaines Google ont leur place [#où-les-domaines-google-ont-leur-place]

`'strict-dynamic'` n'affecte que les scripts. GA4 et GTM font aussi des requêtes non-script : des requêtes de collecte, des images et une frame de debug. Celles-ci sont régies par d'autres directives, et elles ont toujours besoin que les hosts Google soient listés. C'est là que vont les domaines.

* [`connect-src`](/fr/docs/web-security/policies/content-security-policy/directives/connect-src) couvre les appels `fetch` et beacon que GA4 utilise pour envoyer des données. Utilisez des wildcards : `https://*.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com https://www.google.com`. Les wildcards comptent parce que GA4 envoie vers des endpoints de collecte régionaux comme `region1.google-analytics.com`. Un `www.google-analytics.com` nu bloque ce trafic régional.
* [`img-src`](/fr/docs/web-security/policies/content-security-policy/directives/img-src) couvre les requêtes de pixels et d'images : `https://*.google-analytics.com https://*.googletagmanager.com`.
* [`frame-src`](/fr/docs/web-security/policies/content-security-policy/directives/frame-src) couvre la frame Preview et Debug de GTM : `https://www.googletagmanager.com`.

Le mode Preview de GTM et certains tags injectent des styles inline. Si vous voyez des violations de [`style-src`](/fr/docs/web-security/policies/content-security-policy/directives/style-src), préférez un nonce de style ou des hashes précis plutôt que de rouvrir la politique avec [`'unsafe-inline'`](/fr/blog/unsafe-inline-csp). Les styles qu'un conteneur injecte dépendent des tags, donc testez-les contre votre propre conteneur en Report-Only.

Les tags de publicité et de conversion (Google Ads, DoubleClick, Floodlight) atteignent des hosts supplémentaires. N'ajoutez que les hosts dont les tags que votre conteneur déclenche réellement ont besoin, plutôt que d'allowlister tout l'ensemble d'avance. Report-Only vous dira exactement lesquels. Pour les listes de hosts dont d'autres produits Google ont besoin, voyez [CSP pour les services Google](/fr/blog/csp-for-google-services).

## Un exemple de header complet [#un-exemple-de-header-complet]

Voici une politique stricte qui fait tourner GA4 et GTM. Notez que `script-src` ne porte que le nonce et `'strict-dynamic'`, sans aucun host Google :

```http
Content-Security-Policy:
  script-src 'nonce-{SERVER-GENERATED-NONCE}' 'strict-dynamic';
  connect-src 'self' https://*.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com https://www.google.com;
  img-src 'self' https://*.google-analytics.com https://*.googletagmanager.com;
  frame-src https://www.googletagmanager.com;
  object-src 'none';
  base-uri 'none';
  report-uri https://<Endpoint-ID>.report.centralcsp.com;
  report-to csp-endpoint
```

Le `{SERVER-GENERATED-NONCE}` dans le header doit être exactement la même valeur que celle mise sur le script inline d'amorçage. `object-src 'none'` et `base-uri 'none'` sont là parce qu'une politique stricte en a besoin : `base-uri 'none'` en particulier empêche une balise `<base>` injectée de rediriger vos chargements de scripts avec nonce. `report-uri` et `report-to` envoient les reports de violation à votre collecteur pour que vous puissiez observer ce que la politique bloquerait.

## Évitez unsafe-eval, préférez les Custom Templates [#évitez-unsafe-eval-préférez-les-custom-templates]

Une fonctionnalité de GTM casse le schéma strict. Les variables JavaScript personnalisées, et certains tags personnalisés hérités, exécutent du code via `eval`, ce qui exige [`'unsafe-eval'`](/fr/docs/web-security/policies/content-security-policy/values/csp-keywords) dans `script-src`. Ce mot-clé réactive l'exécution de chaîne-vers-code sur toute votre page, ce qui est un véritable affaiblissement de la politique. Pour le tableau complet, voyez [unsafe-eval et pourquoi les Custom JS de GTM en ont besoin](/fr/blog/unsafe-eval-csp).

Préférez les Custom Templates de GTM, qui sont sandboxés et n'ont pas besoin de `'unsafe-eval'`. Si un tag de votre conteneur force `'unsafe-eval'`, traitez-le comme une cible de migration : reconstruisez-le en Custom Template pour pouvoir abandonner le mot-clé. Évitez d'ajouter `'unsafe-eval'` juste pour faire fonctionner une seule variable.

## unsafe-inline n'est pas l'approche [#unsafe-inline-nest-pas-lapproche]

Vous verrez peut-être le conseil d'ajouter `'unsafe-inline'` pour que le script d'amorçage GTM s'exécute. Ne le faites pas. `'unsafe-inline'` réactive chaque script inline de la page, y compris ceux qu'un attaquant injecte, ce qui est exactement ce que la CSP est là pour bloquer. Le raisonnement complet est dans [pourquoi ne jamais utiliser unsafe-inline en CSP](/fr/blog/unsafe-inline-csp).

Cela n'aide même pas ici. Dès qu'une directive contient un nonce ou `'strict-dynamic'`, le navigateur ignore `'unsafe-inline'` dans cette même directive. C'est le nonce sur le script d'amorçage qui fait tourner GTM, donc `'unsafe-inline'` est à la fois dangereux et inerte.

## Testez en Report-Only avant d'imposer [#testez-en-report-only-avant-dimposer]

Les conteneurs GTM changent au fur et à mesure que votre équipe ajoute des tags, et chaque tag peut atteindre un host Google que votre politique n'a pas autorisé. Déployez cette politique d'abord sur le header `Content-Security-Policy-Report-Only`. Le navigateur ne bloque rien et signale tout ce qu'il aurait bloqué, donc vous voyez le host exact dont un nouveau tag a besoin avant qu'il ne puisse casser l'analytics en production.

[CentralCSP](/platform/csp-builder) collecte ces reports de violation Report-Only, les regroupe par directive et origine, et affiche les scripts qui tournent sur chaque page, pour que vous voyiez précisément quel host Google un tag veut avant d'imposer. Vous pouvez [démarrer un essai gratuit](/register), pointer un header Report-Only dessus, et regarder les reports arriver depuis du trafic réel. Pour auditer une politique qu'un site en production envoie déjà, le [scanner CSP](/tools/csp-scanner) la vérifie, et l'[évaluateur CSP](/tools/csp-evaluator) la note pour des faiblesses comme une allowlist de hosts égarée ou un `object-src` manquant.

## Questions fréquentes [#questions-fréquentes]

### Dois-je ajouter googletagmanager.com à script-src ? [#dois-je-ajouter-googletagmanagercom-à-script-src-]

Non. Avec un nonce et `'strict-dynamic'` dans `script-src`, le navigateur ignore les allowlists de hosts pour les scripts. Vous mettez le nonce sur le script d'amorçage GTM à la place, et `'strict-dynamic'` fait confiance à `gtm.js` et aux tags que GTM charge.

### Pourquoi GA4 est-il encore bloqué avec le bon script-src ? [#pourquoi-ga4-est-il-encore-bloqué-avec-le-bon-script-src-]

Parce que GA4 envoie des données via `connect-src`, pas `script-src`. Ajoutez `https://*.google-analytics.com` et les hosts Google associés à `connect-src`. Utilisez le wildcard pour que les endpoints régionaux comme `region1.google-analytics.com` soient autorisés.

### GTM exige-t-il unsafe-eval ? [#gtm-exige-t-il-unsafe-eval-]

Seulement si vous utilisez des variables JavaScript personnalisées ou certains tags personnalisés hérités. Reconstruisez-les en Custom Templates de GTM, qui sont sandboxés et tournent sans `'unsafe-eval'`, pour pouvoir garder le mot-clé hors de votre politique.

### Puis-je vraiment faire tourner GTM avec une CSP stricte basée sur un nonce ? [#puis-je-vraiment-faire-tourner-gtm-avec-une-csp-stricte-basée-sur-un-nonce-]

Oui. Utilisez le snippet d'amorçage officiel de Google qui propage le nonce, mettez le nonce par réponse dessus et dans le header CSP, et ajoutez `'strict-dynamic'`. C'est la configuration CSP stricte prise en charge pour GTM et GA4.

## À retenir [#à-retenir]

Une CSP stricte et Google Analytics ne sont pas en conflit. Mettez un nonce frais par réponse sur le script d'amorçage GTM, ajoutez `'strict-dynamic'` à `script-src`, et laissez la confiance se propager à `gtm.js` et aux tags qu'il charge. Gardez les hosts Google hors de `script-src`, où ils sont ignorés, et ajoutez-les à `connect-src`, `img-src` et `frame-src`, où les requêtes se produisent réellement. Évitez `'unsafe-eval'` en préférant les Custom Templates, et testez le tout en Report-Only d'abord pour qu'un nouveau tag ne casse jamais l'analytics en production.

Pour aller plus loin : le [guide CSP de MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP) et les [recommandations GTM et CSP](https://developers.google.com/tag-platform/security/guides/csp) de Google.
