Headers de sécurité HTTP sur Next.js : comment j'ai fait passer mon site de F à A
Développement Web

Headers de sécurité HTTP sur Next.js : comment j'ai fait passer mon site de F à A

4 mai 20267 min de lecturePar Ahmad Al-Kardali
Retour au blog

Mon site avait un score F sur securityheaders.com. Voici comment je l'ai corrigé en 30 minutes.

Si vous ne savez pas ce qu'est securityheaders.com, c'est simple : entrez l'URL de votre site, et vous obtenez une note de A+ à F selon les headers HTTP de sécurité que votre serveur envoie (ou n'envoie pas).

La plupart des sites vitrine — même bien construits — obtiennent D ou F par défaut. Pas parce que le code est mauvais, mais parce que personne n'a jamais pensé à configurer ces headers.

Voici comment j'ai fait passer ascendixweb.ch de F à A, et comment vous pouvez faire pareil sur votre projet Next.js.

Pourquoi les headers de sécurité comptent

Un header HTTP, c'est une instruction que votre serveur envoie au navigateur avec chaque réponse. La plupart servent à transporter du contenu (Content-Type, Cache-Control…), mais certains servent à dire au navigateur comment se comporter pour protéger l'utilisateur.

Sans ces headers :

  • N'importe qui peut embarquer votre site dans un iframe invisible pour piéger vos visiteurs (clickjacking)
  • Un attaquant peut injecter du JavaScript malveillant qui s'exécute dans le contexte de votre site (XSS)
  • Votre site peut être chargé en HTTP même si vous avez HTTPS (downgrade attack)

Ces attaques ne visent pas uniquement les grandes plateformes. Un site vitrine de PME est une cible parfaite — les visiteurs lui font confiance.

La configuration dans next.config.mjs

Next.js permet d'ajouter des headers HTTP via la fonction headers() dans next.config.mjs. Voici la configuration complète que j'ai mise en place :

const isDev = process.env.NODE_ENV === "development";

const ContentSecurityPolicy = [
  "default-src 'self'",
  `script-src 'self' 'unsafe-inline'${isDev ? " 'unsafe-eval'" : ""} https://www.googletagmanager.com https://www.google-analytics.com`,
  "style-src 'self' 'unsafe-inline'",
  "img-src 'self' data: blob: https://images.unsplash.com https://cdn.jsdelivr.net https://www.google-analytics.com",
  "font-src 'self' data:",
  "connect-src 'self' https://www.google-analytics.com https://analytics.google.com https://vitals.vercel-insights.com",
  "frame-src 'none'",
  "object-src 'none'",
  "base-uri 'self'",
  "form-action 'self'",
].join("; ");

const securityHeaders = [
  { key: "X-Frame-Options",              value: "SAMEORIGIN" },
  { key: "X-Content-Type-Options",       value: "nosniff" },
  { key: "Referrer-Policy",              value: "strict-origin-when-cross-origin" },
  { key: "Permissions-Policy",           value: "camera=(), microphone=(), geolocation=()" },
  { key: "Cross-Origin-Opener-Policy",   value: "same-origin" },
  { key: "Strict-Transport-Security",    value: "max-age=63072000; includeSubDomains; preload" },
  { key: "Content-Security-Policy",      value: ContentSecurityPolicy },
];

const nextConfig = {
  async headers() {
    return [{ source: "/(.*)", headers: securityHeaders }];
  },
  // ... reste de la config
};

Ce que fait chaque header

X-Frame-Options: SAMEORIGIN

Empêche votre site d'être embarqué dans un <iframe> sur un domaine tiers. Protection directe contre le clickjacking — une technique où un attaquant superpose votre site invisible sur le sien pour capturer des clics.

X-Content-Type-Options: nosniff

Interdit au navigateur de "deviner" le type MIME d'un fichier. Sans ce header, un fichier .txt téléversé par un utilisateur pourrait être interprété comme du JavaScript exécutable.

Referrer-Policy: strict-origin-when-cross-origin

Contrôle quelles informations sont transmises dans le header Referer lors de la navigation. Avec cette valeur, l'URL complète est envoyée en navigation same-origin, mais seul le domaine (sans le chemin) est envoyé vers des domaines externes — et rien du tout en HTTP.

Permissions-Policy

Désactive explicitement l'accès à des APIs sensibles du navigateur que votre site n'utilise pas : caméra, microphone, géolocalisation. Même si du code tiers malveillant était injecté, il ne pourrait pas les activer.

Cross-Origin-Opener-Policy: same-origin

Isole votre page des fenêtres cross-origin. Protection contre certaines attaques qui exploitent la référence window.opener entre onglets.

Strict-Transport-Security (HSTS)

Force HTTPS pour 2 ans (max-age=63072000), sur tous les sous-domaines (includeSubDomains), et rend le domaine éligible à la preload list des navigateurs. Une fois dans cette liste, Chrome et Firefox forcent HTTPS avant même d'envoyer une requête — impossible de downgrader vers HTTP.

Content-Security-Policy (CSP)

Le plus puissant et le plus complexe. Il définit une liste blanche des sources autorisées pour chaque type de ressource : scripts, styles, images, connexions réseau… Un script qui ne figure pas dans la whitelist est bloqué par le navigateur, même s'il a été injecté via une faille XSS.

Attention avec Next.js : si vous utilisez des scripts JSON-LD en dangerouslySetInnerHTML, vous aurez besoin de 'unsafe-inline' dans script-src. La solution propre serait d'utiliser des nonces, mais c'est significativement plus complexe à mettre en place avec l'App Router.

Un piège classique : oublier les ressources externes

Après avoir déployé ma CSP, les icônes de la section "Stack technique" avaient disparu. La raison : elles sont chargées depuis cdn.jsdelivr.net, que j'avais oublié dans img-src.

La méthode pour déboguer : ouvrez la console du navigateur. Chaque ressource bloquée par la CSP génère une erreur précise qui indique exactement quel domaine ajouter et dans quelle directive.

Refused to load the image 'https://cdn.jsdelivr.net/...'
because it violates the following Content Security Policy directive: "img-src 'self'"

Vérifier le résultat

Une fois déployé, allez sur securityheaders.com et entrez votre URL. Vous verrez immédiatement quels headers sont présents, lesquels manquent, et une note globale.

Avant : F (aucun header de sécurité) Après : A (tous les headers critiques présents)

Le score A+ nécessite Content-Security-Policy-Report-Only et une CSP sans 'unsafe-inline', ce qui demande une implémentation avec nonces — un sujet pour un prochain article.

Ce qui ne se configure pas dans le code : le DKIM

Le DKIM (DomainKeys Identified Mail) est une signature cryptographique ajoutée à vos e-mails sortants qui prouve qu'ils viennent bien de votre domaine. Ça ne se configure pas dans Next.js — ça se fait dans l'interface de votre hébergeur DNS (Infomaniak dans mon cas).

Si vous avez déjà SPF et DMARC en place (ce qui est bien), le DKIM est la dernière pièce pour une protection e-mail complète contre le spoofing.

En résumé

Ajouter des headers de sécurité sur un site Next.js prend moins d'une heure. Le gain est immédiat : meilleure protection des visiteurs, score securityheaders.com honorable, et une crédibilité renforcée si un client technique inspecte votre site.

Ce n'est pas parce qu'un site vitrine ne gère pas de paiements ou de comptes utilisateurs qu'il ne mérite pas d'être sécurisé. Vos visiteurs vous font confiance — autant ne pas les décevoir.

Tags :#Sécurité#Next.js#HTTP Headers#CSP#Performance

Besoin d'aide ?

Confiez votre projet à un expert web en Valais

Partager cet article

Articles Similaires

4 mai 20268 min

WordPress vs Next.js en 2026 : lequel choisir pour votre site ?

WordPress ou Next.js ? Comparaison complète en 2026 : performance, SEO, coût, facilité d'utilisation. Quel CMS choisir pour votre projet en Suisse ?

#WordPress#Next.js#CMS
9 mars 20267 min

Next.js 16.2 vient de sortir : ce que ça change concrètement pour vos projets

87% de démarrage plus rapide, rendu serveur jusqu'à 60% plus rapide, logs des Server Functions, meilleur debug des erreurs d'hydratation. Tour d'horizon des nouveautés Next.js 16.2 qui changent le quotidien.

#Next.js#Turbopack#Performance
17 février 20267 min

CSS natif en 2026 : pourquoi Tailwind n'est plus la seule option

Container queries, :has(), nesting natif, view transitions — le CSS de 2026 fait ce que JavaScript et Sass faisaient avant. Tour d'horizon des fonctionnalités qui changent la donne.

#CSS#Tailwind#Développement Web