Use Cases (Mis à jour: 02/06/2026)

En-têtes de sécurité web avec Claude Code : CSP, nonce, HSTS et déploiement sans casse

Configurez CSP, nonce, HSTS, frame-ancestors et les en-têtes de sécurité avec Claude Code.

En-têtes de sécurité web avec Claude Code : CSP, nonce, HSTS et déploiement sans casse

Les en-têtes de sécurité web paraissent modestes, mais ils changent concrètement ce qu’un navigateur est autorisé à faire. Ils limitent les scripts exécutables, empêchent une page d’administration d’être intégrée dans un iframe hostile, réduisent les fuites de referrer et désactivent des fonctionnalités comme la caméra, le microphone ou la géolocalisation lorsqu’elles ne sont pas nécessaires.

Claude Code est très utile pour ce travail : il peut lire le dépôt, repérer les scripts tiers, modifier la configuration d’un framework et proposer des commandes de vérification. Mais une consigne vague peut produire une politique dangereusement large. Si vous demandez seulement « corrige les erreurs CSP », vous risquez d’obtenir script-src * 'unsafe-inline' 'unsafe-eval'. Les erreurs disparaissent, mais la protection aussi.

La méthode robuste consiste à inventorier les ressources, activer Content-Security-Policy-Report-Only, analyser les rapports, puis renforcer la politique par route. Ce guide couvre CSP, nonce, HSTS, X-Frame-Options, frame-ancestors, Referrer-Policy et Permissions-Policy, avec des exemples pour Next.js, Astro, Express et Cloudflare Pages. Il traite aussi des rapports CSP, de Security Headers, de CSP Evaluator et des conflits fréquents avec Google Tag Manager, Google Analytics, AdSense, les images et les CDN. Pour sécuriser Claude Code lui-même, lisez aussi les bonnes pratiques de sécurité Claude Code et l’audit de sécurité.

Gardez les sources officielles à portée de main : MDN Content-Security-Policy, Next.js CSP guide, MDN Strict-Transport-Security, hstspreload.org, Cloudflare Pages Headers, Helmet, Google Tag Manager CSP et AdSense avec CSP.

Commencer par l’inventaire des ressources

Ne commencez pas par copier une politique CSP trouvée ailleurs. Demandez d’abord à Claude Code ce que votre site charge réellement.

Conçois les en-têtes de sécurité web de ce dépôt.
Contraintes :
- Lister d'abord les origines externes pour script, style, image, font, frame et connect.
- Déployer CSP en Report-Only avant l'application stricte.
- Éviter * et unsafe-inline permanent.
- Si Next.js utilise un nonce, expliquer l'impact sur le rendu dynamique et le cache.
- Vérifier Google Analytics, GTM, AdSense, les CDN d'images et les iframes YouTube.
- Fournir les vérifications curl, Security Headers et CSP Evaluator.

Cette étape évite la confusion entre directives. frame-src indique ce que votre page peut intégrer. frame-ancestors indique qui peut intégrer votre page. Les erreurs Google Analytics relèvent souvent de connect-src, les images CDN de img-src, et la protection contre le clickjacking de frame-ancestors.

En-têtePoint de départAttention
Content-Security-PolicyD’abord Content-Security-Policy-Report-OnlyNe pas masquer les problèmes avec *
Strict-Transport-Securitymax-age=300; includeSubDomains au débutpreload seulement si tous les sous-domaines sont prêts
X-Frame-OptionsDENY ou SAMEORIGINframe-ancestors est plus précis
Referrer-Policystrict-origin-when-cross-originNe jamais mettre de secrets dans l’URL
Permissions-PolicyDésactiver les capacités inutilesAutoriser seulement ce que le produit utilise
X-Content-Type-OptionsnosniffSimple et utile sur tout le site

HSTS preload doit rester une décision explicite. Le site officiel recommande une montée progressive du max-age et prévient qu’une inclusion est difficile à annuler rapidement. Un vieux sous-domaine de test ou un domaine de tracking sans HTTPS peut devenir une panne visible.

Déployer CSP par observation

Le bon flux est : observer, classer, renforcer.

flowchart LR
  A["Inventaire des ressources"] --> B["CSP Report-Only"]
  B --> C["Console navigateur et rapports"]
  C --> D["Classer annonces, analytics, CDN, iframes et bruit"]
  D --> E["CSP avec nonce ou hash"]
  E --> F["Security Headers et CSP Evaluator"]

Ne copiez pas tous les domaines présents dans les rapports. Les extensions navigateur, les proxys d’entreprise, les anciens tags et les tentatives malveillantes peuvent produire du bruit. Claude Code peut regrouper ces signaux, mais la décision doit rester liée à un besoin produit.

Next.js avec nonce

La documentation actuelle de Next.js App Router utilise proxy.ts pour générer un nonce à chaque requête. Certains projets plus anciens utilisent encore middleware.ts, mais le principe reste identique : créer une valeur aléatoire, la passer dans les headers de requête, puis l’utiliser dans script-src.

Un nonce par requête a un coût : il force du rendu dynamique pour les pages qui en ont besoin. Pour un blog statique ou une landing page, des hashes CSP ou des scripts externes peuvent être plus adaptés. Pour un checkout, un espace client ou une administration, le nonce est souvent justifié.

// proxy.ts
import { NextRequest, NextResponse } from "next/server";

export function proxy(request: NextRequest) {
  const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
  const isDev = process.env.NODE_ENV !== "production";

  const csp = [
    "default-src 'self'",
    `script-src 'self' 'nonce-${nonce}' 'strict-dynamic' ${isDev ? "'unsafe-eval'" : ""} https: http:`,
    `style-src 'self' ${isDev ? "'unsafe-inline'" : `'nonce-${nonce}'`} https://fonts.googleapis.com`,
    "font-src 'self' https://fonts.gstatic.com",
    "img-src 'self' data: blob: https:",
    "connect-src 'self' https://www.google-analytics.com https://analytics.google.com",
    "frame-src 'self' https://www.youtube-nocookie.com",
    "object-src 'none'",
    "base-uri 'self'",
    "form-action 'self'",
    "frame-ancestors 'none'",
    "upgrade-insecure-requests",
    "report-uri /api/csp-report",
  ].join("; ").replace(/\s{2,}/g, " ").trim();

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set("x-nonce", nonce);

  const response = NextResponse.next({ request: { headers: requestHeaders } });
  response.headers.set("Content-Security-Policy", csp);
  response.headers.set("X-Content-Type-Options", "nosniff");
  response.headers.set("X-Frame-Options", "DENY");
  response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
  response.headers.set("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=(self)");
  response.headers.set("Strict-Transport-Security", "max-age=300; includeSubDomains");
  return response;
}

export const config = {
  matcher: ["/((?!api/csp-report|_next/static|_next/image|favicon.ico).*)"],
};

Pour Google Tag Manager, transmettez le nonce au composant ou au snippet. GTM démarre avec du JavaScript inline, et Google recommande l’approche nonce. AdSense documente aussi le strict CSP, car les domaines publicitaires peuvent évoluer. Une simple allowlist peut casser la monétisation plus tard.

Recevoir les rapports CSP

Avant d’appliquer la politique stricte, créez un endpoint de rapport. Exemple minimal avec Next.js :

// app/api/csp-report/route.ts
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  const contentType = request.headers.get("content-type") ?? "";
  const body = await request.text();

  const isReport =
    contentType.includes("application/csp-report") ||
    contentType.includes("application/reports+json") ||
    body.includes("violated-directive");

  if (!isReport) {
    return NextResponse.json({ ok: false }, { status: 415 });
  }

  console.warn("csp-report", body.slice(0, 4000));
  return new NextResponse(null, { status: 204 });
}

En production, évitez de stocker des URLs complètes si elles peuvent contenir des données personnelles. Conservez plutôt la route, la directive violée, l’URI bloquée, le navigateur, l’heure et le compteur. report-uri est ancien, mais reste utile pour la compatibilité. report-to peut être ajouté en complément.

Astro, Express et Cloudflare

Astro permet d’ajouter des headers dans src/middleware.ts. Pour un site surtout statique, réduire les scripts inline est souvent plus simple que générer des nonces.

// src/middleware.ts
import { defineMiddleware } from "astro:middleware";

const securityHeaders: Record<string, string> = {
  "Content-Security-Policy-Report-Only": "default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: blob: https:; connect-src 'self' https://www.google-analytics.com; frame-src 'self' https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-uri /api/csp-report",
  "X-Content-Type-Options": "nosniff",
  "X-Frame-Options": "DENY",
  "Referrer-Policy": "strict-origin-when-cross-origin",
  "Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=(self)",
};

export const onRequest = defineMiddleware(async (_context, next) => {
  const response = await next();
  for (const [name, value] of Object.entries(securityHeaders)) {
    response.headers.set(name, value);
  }
  return response;
});

Pour Express, Helmet donne une base solide, mais la CSP doit rester spécifique à votre application.

import crypto from "node:crypto";
import express from "express";
import helmet from "helmet";

const app = express();

app.use((req, res, next) => {
  res.locals.cspNonce = crypto.randomBytes(16).toString("base64");
  next();
});

app.use(helmet({
  contentSecurityPolicy: {
    useDefaults: false,
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`, "'strict-dynamic'", "https:", "http:"],
      imgSrc: ["'self'", "data:", "blob:", "https:"],
      connectSrc: ["'self'", "https://www.google-analytics.com"],
      objectSrc: ["'none'"],
      baseUri: ["'self'"],
      frameAncestors: ["'none'"],
      reportUri: ["/csp-report"],
    },
  },
  strictTransportSecurity: { maxAge: 300, includeSubDomains: true },
  referrerPolicy: { policy: "strict-origin-when-cross-origin" },
  xFrameOptions: { action: "deny" },
}));

Cloudflare Pages accepte un fichier _headers, mais ce fichier ne peut pas générer de nonce par requête.

/*
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(self)
  Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: blob: https:; connect-src 'self' https://www.google-analytics.com; frame-src 'self' https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-uri /csp-report

Cas d’usage et pièges fréquents

Un site de contenu avec GA4, GTM, AdSense, des polices et des images CDN doit protéger ses pages sans interrompre les revenus. Le bon réflexe est de passer par Report-Only, puis de vérifier l’affichage des annonces, les événements Analytics, les images et les iframes.

Une application SaaS privée a une priorité différente : moins de scripts tiers et une politique plus stricte. Les routes d’administration peuvent utiliser frame-ancestors 'none', object-src 'none', base-uri 'self' et un form-action limité. Les SDK de paiement ou de support doivent être autorisés seulement sur les routes nécessaires.

Un widget intégrable demande une politique séparée. Si vos clients doivent l’intégrer en iframe, X-Frame-Options: DENY est faux pour cette route. Utilisez des headers par route et des domaines autorisés dans frame-ancestors.

Vérification et résultat observé

Vérifiez au moins la page d’accueil, une page de formulaire ou de connexion, et une route d’embed ou de paiement.

curl -I https://example.com/
curl -I https://example.com/login
curl -I https://example.com/embed/widget

Utilisez ensuite Security Headers pour une vue globale et CSP Evaluator pour la qualité CSP. Le score n’est pas l’objectif final : l’objectif est une politique juste, qui protège sans casser publicité, analytics, paiement ou intégrations légitimes.

Lors du test préparé pour cet article, le passage par Report-Only a immédiatement séparé les problèmes : nonce GTM, connect-src GA4, frame-src YouTube et img-src CDN. Claude Code a pu classer les rapports et proposer une politique par route au lieu d’ajouter aveuglément des domaines. Pour appliquer cette démarche à un dépôt réel, utilisez la page formation et conseil Claude Code ou les templates ClaudeCodeLab afin d’en faire une règle de revue dans CLAUDE.md.

#Claude Code #security #HTTP headers #CSP #web development
Gratuit

PDF gratuit: cheatsheet Claude Code

Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.

Nous protégeons vos données et n'envoyons pas de spam.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.