Content-Security-Policy sur une landing page : cadrer GTM, Meta Pixel et Stripe sans tout bloquer
Publié le 1 septembre 2026 · 8 min de lecture
Un visiteur qui arrive sur une landing page depuis une publicité Meta ou une campagne Google Ads déclenche, sans le savoir, l'exécution d'une demi-douzaine de scripts qu'aucune ligne de code du site n'a écrits directement : le conteneur Google Tag Manager, le pixel Meta, le tag de conversion Google Ads, parfois un widget d'avis clients, et au moment du paiement le script de js.stripe.com. Le navigateur exécute chacun d'eux avec exactement le même niveau de confiance que le code écrit par l'équipe elle-même. Par défaut, il n'existe aucune règle qui distingue « ce script vient de Google et je l'ai ajouté volontairement » de « ce script vient d'un provider tiers compromis et personne ne l'a jamais vu passer ». L'en-tête HTTP Content-Security-Policy (CSP) sert exactement à poser cette règle : une liste blanche de ce qui a le droit de s'exécuter, appliquée par le navigateur lui-même, indépendamment de ce que contient le HTML de la page.
Pourquoi une landing page sans compte utilisateur reste concernée
L'objection la plus fréquente : une landing page n'a ni espace membre ni données sensibles à protéger, donc la CSP semblerait réservée aux applications avec authentification. Le raisonnement rate la vraie surface d'attaque. Une landing page reste une page web qui accepte de l'input — un formulaire de capture de leads, parfois un champ d'avis ou de commentaire — et qui embarque du contenu affiché dynamiquement, comme un widget de témoignages tiers ou une balise Google reCAPTCHA. Chacun de ces points est une porte d'entrée théorique pour une injection de script (XSS) : si un attaquant parvient à faire passer une chaîne de caractères malveillante par l'un de ces canaux, la CSP est la seule barrière qui empêche encore ce script de s'exécuter, une fois que la validation côté serveur a déjà été contournée. C'est une défense en profondeur, pas une protection contre un scénario improbable : elle ne remplace pas la validation des entrées, elle rattrape ce que la validation aurait laissé passer.
Ce que fait réellement une directive CSP
Une politique CSP se compose de directives, chacune limitant une catégorie de ressource à une liste de sources autorisées. script-src contrôle quels domaines ont le droit de fournir du JavaScript exécutable ; style-src fait la même chose pour les feuilles de style ; img-src, connect-src (appels réseau fetch/XHR) et frame-src (contenu affiché en iframe, comme un widget Stripe) couvrent le reste. Toute ressource qui tente de charger depuis un domaine absent de la liste correspondante est bloquée par le navigateur, silencieusement pour le visiteur mais signalée dans la console développeur — et, si l'en-tête report-uri ou report-to est configuré, remontée sous forme de rapport JSON envoyé à une URL choisie. C'est ce canal de reporting qui permet de découvrir, sans attendre un incident, qu'un widget mal codé essaie de charger une ressource depuis un domaine non prévu.
Les domaines à autoriser pour la pile tracking + paiement d'une landing page
Le point de blocage le plus fréquent d'une première CSP est le nombre de sous-domaines que chaque outil marketing utilise réellement — souvent plus que ce que documente sa page d'installation. Le tableau suivant couvre la pile typique d'une landing page qui utilise Google Tag Manager, le pixel Meta et Stripe pour le paiement.
| Outil | Directive | Domaines |
|---|---|---|
| Google Tag Manager | script-src | *.googletagmanager.com |
| GA4 (chargé via GTM) | connect-src | *.google-analytics.com, *.analytics.google.com |
| Pixel Meta | script-src, connect-src | connect.facebook.net, *.facebook.com |
| Google Ads (conversion) | script-src, connect-src | *.googleadservices.com, *.google.com |
| Stripe (Checkout) | script-src, frame-src, connect-src | js.stripe.com, checkout.stripe.com, api.stripe.com |
| Polices Google (si non auto-hébergées) | style-src, font-src | fonts.googleapis.com, fonts.gstatic.com |
Un détail qui piège systématiquement une première configuration : Google Tag Manager charge lui-même d'autres scripts une fois exécuté (GA4, un pixel ajouté depuis son interface), qui proviennent de domaines différents du conteneur GTM initial. Autoriser uniquement googletagmanager.com et oublier google-analytics.com fait apparaître un conteneur qui se charge, mais des tags qui échouent silencieusement à l'intérieur — un scénario qui casse le tracking sans jamais faire planter la page, donc difficile à repérer sans consulter la console ou les rapports CSP.
L'erreur qui neutralise toute la politique : unsafe-inline par réflexe
Face à un script inline qui casse (souvent le fragment de configuration GTM collé directement dans le <head>, ou un gestionnaire onclick écrit à la main), le réflexe le plus rapide est d'ajouter 'unsafe-inline' à script-src. Cette directive autorise n'importe quel script inline à s'exécuter, y compris celui qu'un attaquant parviendrait à injecter — ce qui annule la protection XSS que la CSP est censée apporter. Une étude de Calzavara, Rabitti et Bugliesi (« Content Security Problems? Evaluating the Effectiveness of Content Security Policy in the Wild », CCS 2016) a analysé un grand nombre de politiques CSP réellement déployées sur le web et constaté que la majorité contenait des erreurs de configuration qui en annulaient l'essentiel de l'effet — unsafe-inline étant l'une des causes les plus fréquentes. L'alternative correcte est un nonce (une valeur aléatoire générée à chaque requête, ajoutée à la fois dans l'en-tête CSP et sur la balise <script> autorisée) ou un hash du contenu exact du script inline : plus de configuration au départ, mais une politique qui protège réellement contre un script injecté, puisqu'il n'aura ni le bon nonce ni le bon hash.
L'implémenter sur Next.js
Sur un projet Next.js comme les templates LanderKit, l'en-tête se déclare sans middleware ni route API dédiée, directement dans next.config.ts via la fonction headers() : une entrée avec source: "/(.*)" applique l'en-tête Content-Security-Policy à toutes les routes, avec la chaîne de directives (default-src 'self'; script-src 'self' *.googletagmanager.com js.stripe.com; frame-src js.stripe.com checkout.stripe.com; connect-src 'self' *.google-analytics.com api.stripe.com; …) construite à partir du tableau ci-dessus. Pour une page entièrement statique — le cas de chaque page /templates/[slug] de ce site, couvert par l'article sur la stratégie de cache Next.js/Vercel — cet en-tête est posé une fois au build et servi tel quel depuis le CDN, sans coût de calcul à la requête : la CSP n'ajoute aucune latence perceptible, contrairement à ce que son nom technique laisse parfois craindre.
Tester sans rien casser : le mode report-only
Déployer directement une CSP stricte en production revient à parier qu'aucun script légitime ne sera bloqué par erreur — un pari risqué sur une page dont la conversion dépend justement du bon fonctionnement du tracking publicitaire. L'en-tête Content-Security-Policy-Report-Only résout ce risque : il applique exactement les mêmes règles, mais ne bloque rien — il se contente d'enregistrer, via report-to, chaque violation qui se serait produite. Faire tourner cette version pendant quelques jours de trafic réel révèle les domaines oubliés dans le tableau initial, avant de basculer sur l'en-tête bloquant définitif une fois la liste stabilisée.
Le risque que la CSP ne couvre pas : la confiance accordée au script lui-même
Autoriser un domaine dans script-src ne garantit rien sur le contenu que ce domaine sert : si le CDN d'un widget d'avis tiers est compromis, ou si le provider modifie son script pour y inclure du code indésirable, la CSP n'y changera rien tant que le domaine reste dans la liste blanche — elle protège contre un script inconnu, pas contre un script de confiance devenu malveillant. Une étude de Nikiforakis et al. (« You Are What You Include: Large-scale Evaluation of Remote JavaScript Inclusions », CCS 2012), menée sur plus de trois millions de pages, a montré qu'une part significative des sites les plus visités du web font confiance à des providers de scripts tiers dont l'infrastructure de maintenance présentait des failles exploitables. La conclusion pratique pour une landing page : limiter le nombre de scripts tiers embarqués au strict nécessaire — c'est déjà l'esprit de l'article sur GTM et le seuil à partir duquel il devient utile — reste une mesure de sécurité à part entière, pas seulement un réflexe de performance.
Une CSP bien réglée ne se voit jamais dans le design d'une landing page, tout comme une bonne stratégie de cache ou un Cache-Control correctement posé : elle ne convertit personne à elle seule, mais elle transforme un script tiers compromis d'incident potentiel en simple ligne bloquée dans une console. Les templates LanderKit (89 € l'unité, 229 € le pack de 10) sont livrés comme des projets Next.js statiques, pensés pour être déployés sur Vercel avec un next.config.ts déjà en place — y ajouter un en-tête CSP adapté à sa propre pile de tracking ne demande qu'une liste de domaines, pas une refonte.
FAQ
Questions fréquentes
Une CSP va-t-elle bloquer Google Tag Manager ou le pixel Meta par défaut ?
Oui, si le domaine correspondant n'est pas explicitement ajouté à la directive script-src (et connect-src pour les appels réseau qu'ils déclenchent). C'est pour cette raison qu'il vaut mieux commencer en mode Content-Security-Policy-Report-Only : la politique tourne sans rien bloquer et révèle les domaines oubliés avant de passer en version bloquante.
Pourquoi ne pas simplement ajouter 'unsafe-inline' pour éviter les erreurs de configuration ?
Parce que cette directive autorise n'importe quel script inline à s'exécuter, y compris celui qu'un attaquant injecterait via une faille XSS — ce qui annule la principale protection qu'une CSP est censée apporter. Un nonce ou un hash demande un peu plus de configuration mais garde la politique réellement protectrice.
Une landing page sans espace membre a-t-elle vraiment besoin d'une CSP ?
Oui, dès qu'elle contient un formulaire ou un widget affichant du contenu dynamique (avis clients, commentaires) : ce sont des points d'entrée théoriques pour une injection de script. La CSP est une défense en profondeur qui rattrape ce qu'une validation d'entrée aurait laissé passer, pas une protection réservée aux sites avec compte utilisateur.
Où déclarer l'en-tête Content-Security-Policy sur un projet Next.js ?
Le plus simple est la fonction headers() de next.config.ts, avec une règle appliquée à toutes les routes (source: "/(.*)"). Pour une page statique, l'en-tête est posé une fois au build et servi depuis le CDN sans coût de calcul à la requête.
À lire ensuite
Articles liés
- Tag Manager côté serveur (sGTM) sur une landing page : faut-il vraiment s’y mettreUn conteneur Google Tag Manager qui tourne sur un serveur plutôt que dans le navigateur du visiteur : c’est la promesse du tag manager côté serveur, vendu comme le remède aux bloqueurs de publicité et à l’ITP de Safari. La recherche a pourtant trouvé des fuites de données jusque côté serveur, et l’infrastructure a un coût qu’on oublie de mentionner. Ce qui justifie vraiment de s’y mettre — et ce qui n’en a pas besoin.
- La Speculation Rules API : rendre le clic sur le CTA d’une landing page vraiment instantanéUn visiteur clique sur « Réserver une démo » ou « Rejoindre la liste d’attente », et attend un instant que la page suivante se charge — quelques centaines de millisecondes qui suffisent à faire hésiter. Le prefetch de Next.js télécharge déjà les données de cette page à l’avance, mais pas son rendu. La Speculation Rules API de Chrome va un cran plus loin : elle exécute et affiche la page cible en arrière-plan avant même le clic, pour une navigation qui semble ne prendre aucun temps du tout.
- La balise canonical sur une landing page : pourquoi et comment l’utiliserUne même landing page décline souvent en plusieurs variantes : une URL par source publicitaire, une par ville, une par groupe d’annonces, parfois une par test A/B. Pour un visiteur, ce sont des pages différentes. Pour Google, ce sont des quasi-doublons — et sans balise canonical, le moteur de recherche décide seul laquelle indexer.