Configurer les en‑têtes de sécurité et la CSP pour Strapi + Next.js – guide défensif
Apprenez pas à pas comment ajouter les en‑têtes HTTP essentiels et une CSP stricte à un CMS headless Strapi et à un frontend Next.js, pour vous protéger contre les attaques XSS, le clickjacking et les fuites de données.
Par l’équipe Revisionary · · 5 min de lecture
Comment ajouter des en‑têtes de sécurité et une CSP stricte à un site Strapi + Next.js ?
Ajoutez les en‑têtes HTTP essentielles tant dans la couche API (Strapi) que dans la couche de présentation (Next.js). Utilisez une Content‑Security‑Policy (CSP) qui autorise uniquement les ressources dont vous avez besoin, puis verrouillez le reste avec Helmet, strict‑transport‑security, X‑Frame‑Options et les en‑têtes associés. Les étapes ci‑dessous couvrent la configuration, les tests et la maintenance d’une mise en place défensive de niveau production.
Pourquoi les en‑têtes de sécurité sont importantes
Les en‑têtes de sécurité sont des instructions envoyées par le serveur qui indiquent aux navigateurs comment gérer la réponse. Elles atténuent de nombreuses attaques courantes sans modifier le code de l’application :
| En‑tête | Protection principale | Valeur typique |
|---|---|---|
Content‑Security‑Policy | Cross‑site scripting (XSS), injection de données, contenu mixte | default-src 'self'; script-src 'self' https://cdn.example.com; object-src 'none'; |
X‑Content‑Type‑Options | MIME‑sniffing | nosniff |
X‑Frame‑Options | Clickjacking | DENY ou SAMEORIGIN |
Strict‑Transport‑Security (STS) | Imposition du HTTPS | max-age=31536000; includeSubDomains; preload |
Referrer‑Policy | Fuite du référent | strict-origin-when-cross-origin |
Permissions‑Policy | Contrôle des fonctionnalités du navigateur (camera, géolocalisation…) | geolocation=(), camera=() |
Lorsqu’un CMS headless alimente un framework front‑end, il faut définir ces en‑têtes dans les deux environnements : l’API Strapi (qui sert du JSON) et le serveur Next.js (qui sert du HTML, JS, CSS, images). Ainsi, même si un attaquant compromettait une couche, l’autre appliquerait toujours les mêmes politiques.
Prérequis
- Strapi 5 installé et en cours d’exécution.
- Projet Next.js qui récupère le contenu via l’API REST ou GraphQL de Strapi.
- Accès à la configuration du serveur (environnement Node.js) — aucun reverse‑proxy n’est requis, mais vous pouvez également appliquer les mêmes en‑têtes en bordure (Vercel, Cloudflare) si vous le souhaitez.
- Optionnel : le plugin Revisionary installé si vous désirez un journal d’audit immuable des changements de configuration d’en‑têtes (utile pour la conformité RGPD).
1. Ajouter les en‑têtes de sécurité à Strapi
Strapi ne propose pas de gestionnaire d’en‑têtes intégré, mais vous pouvez utiliser le middleware helmet très répandu. Créez un fichier middleware personnalisé et enregistrez‑le dans config/middleware.ts.
// ./src/middleware/securityHeaders.js
import helmet from 'helmet';
export default helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'"], // ajustez si vous utilisez des styles en ligne
imgSrc: ["'self'", "data:", "https://images.example.com"],
connectSrc: ["'self'", "https://api.example.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
},
// En‑têtes supplémentaires
referrerPolicy: { policy: "strict-origin-when-cross-origin" },
hidePoweredBy: true,
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },
frameguard: { action: "deny" },
noSniff: true,
});Enregistrez maintenant le middleware :
// ./config/middleware.ts
module.exports = [
'strapi::errors',
'strapi::security',
// autres middlewares par défaut …
{
name: 'global::securityHeaders',
// Le chemin est relatif à la racine du projet
resolve: './src/middleware/securityHeaders.js',
},
];Points clés
- Les directives CSP reflètent ce dont le front‑end a besoin. Gardez la liste la plus restreinte possible.
upgradeInsecureRequestsforce les navigateurs à charger les ressources HTTP via HTTPS, évitant ainsi les avertissements de contenu mixte.hidePoweredBysupprime l’en‑têteX-Powered-By: Strapi, limitant les fuites d’informations.
Vérifier les en‑têtes
Démarrez Strapi et interrogez n’importe quel endpoint, par ex. curl -I http://localhost:1337/api/articles. Vous devez voir la liste complète des en‑têtes.
2. Ajouter les en‑têtes de sécurité à Next.js
Next.js vous permet de définir des en‑têtes HTTP personnalisées dans next.config.js via la fonction asynchrone headers. Combinez cela avec le package next-secure-headers pour une configuration concise.
// next.config.js
const { createSecureHeaders } = require('next-secure-headers');
module.exports = {
async headers() {
return [
{
// Appliquer à toutes les routes
source: '/(.*)',
headers: createSecureHeaders({
contentSecurityPolicy: {
// Mêmes directives que Strapi, mais vous pouvez ajouter des sources spécifiques à Next
directives: {
defaultSrc: "'self'",
scriptSrc: ["'self'", "https://cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https://images.example.com"],
connectSrc: ["'self'", "https://api.example.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
objectSrc: "'none'",
upgradeInsecureRequests: true,
},
},
// Autres en‑têtes
referrerPolicy: 'strict-origin-when-cross-origin',
permissionsPolicy: {
camera: [],
microphone: [],
geolocation: [],
},
// HSTS – ne fonctionne que sur les domaines de production en HTTPS
strictTransportSecurity: {
maxAge: 31536000,
includeSubDomains: true,
preload: true,
},
xssProtection: true,
frameGuard: 'deny',
noSniff: true,
}),
},
];
},
};Explication
createSecureHeadersgénère l’ensemble complet des en‑têtes ; vous pouvez personnaliser chaque directive.- La CSP ici correspond à celle de l’API Strapi, assurant que les deux couches s’accordent sur les sources autorisées.
- Déployez sur un hôte compatible HTTPS (Vercel, Netlify, etc.) pour que le HSTS prenne effet.
Tester dans le navigateur
Ouvrez le site sous Chrome, ouvrez les DevTools → Network, sélectionnez le document principal et inspectez l’onglet Response Headers. Vérifiez que chaque en‑tête apparaît une seule fois.
3. Aligner la CSP entre l’API et le front‑end
Comme Strapi renvoie du JSON, la CSP de l’API n’affecte pas directement le navigateur. Cependant, une politique incohérente peut provoquer des échecs de pré‑vol CORS lorsque le front‑end tente de récupérer des ressources depuis l’API.
- Conservez la directive
connect-srcde la CSP du front‑end en phase avec l’origine de l’API. - Si vous utilisez un CDN pour les assets statiques, ajoutez‑le à la fois à
script-srcet àstyle-src. - Lors de l’ajout d’un script d’analyse tiers, mettez à jour les deux CSP simultanément.
4. Automatiser la validation des en‑têtes en CI/CD
Ajoutez un test simple à votre pipeline CI qui échoue si un en‑tête requis est absent. Exemple avec Node fetch et Jest :
// __tests__/securityHeaders.test.js
const fetch = require('node-fetch');
test('L’API renvoie les en‑têtes de sécurité obligatoires', async () => {
const res = await fetch('http://localhost:1337/api/articles');
const headers = res.headers;
expect(headers.get('content-security-policy')).toBeTruthy();
expect(headers.get('strict-transport-security')).toMatch(/max-age=31536000/);
expect(headers.get('x-frame-options')).toBe('DENY');
expect(headers.get('x-content-type-options')).toBe('nosniff');
});Exécutez ce test dans vos GitHub Actions ou tout autre système CI. Si un en‑tête est supprimé ou modifié par inadvertance, le build échoue, empêchant une version vulnérable d’être déployée.
5. Checklist de maintenance continue
| Fréquence | Tâche |
|---|---|
| À chaque nouvelle dépendance | Revoir la CSP afin d’ajouter toute source de script ou de style requise. Mettre à jour les configurations de Strapi et Next.js. |
| Trimestriel | Lancer un scanner CSP (ex. : Mozilla Observatory) contre le site en production. Corriger les violations signalées. |
| Après toute modification d’infrastructure | Vérifier que l’en‑tête strict-transport-security est toujours présent et que le flag preload correspond à l’enregistrement du domaine. |
| Lorsque des données liées au RGPD sont stockées | S’assurer que le journal d’audit (Revisionary) enregistre les changements d’en‑têtes. Anonymiser les IP si nécessaire (/docs/settings/privacy). |
| Après un incident de sécurité | Faire pivoter les tokens secrets (API keys, clés de signature JWT) et ré‑évaluer la CSP face aux nouvelles vecteurs d’attaque. |
6. Pièges courants et comment les éviter
- CSP trop permissive – Utiliser
script-src 'unsafe-inline'annule la protection XSS. Remplacez les scripts inline par des fichiers externes ou utilisez un nonce/hachage si indispensable. - Oubli de
upgrade-insecure-requests– Les navigateurs bloqueront le contenu mixte sur les pages HTTPS, entraînant une UI cassée. Ajoutez cette directive. - En‑têtes dupliqués – Si vous définissez les en‑têtes à la fois dans un reverse‑proxy (ex. : Nginx) et dans l’application, le navigateur peut recevoir deux valeurs et ignorer la politique. Choisissez une source de vérité unique.
- Sous‑domaines oubliés – STS ne s’applique qu’au domaine qui envoie l’en‑tête. Ajoutez
includeSubDomainset inscrivez le domaine sur la liste de pré‑chargement HSTS si vous possédez des sous‑domaines. - Rapports de violation CSP ignorés – Activez
report-urioureport-todans la CSP pour collecter les rapports de violation. Utilisez un endpoint léger (ex. : un type de collection Strapi) pour les stocker et les analyser plus tard.
7. Lier Revisionary pour la conformité d’audit (optionnel)
Si votre organisation doit prouver que les configurations d’en‑têtes n’ont pas été altérées, activez le journal d’audit de Revisionary. Chaque modification de config/middleware.ts ou de next.config.js doit être commitée via le pipeline CI qui crée également une entrée versionnée dans le CMS. Le journal (/docs/everyday-use/audit) indique qui a changé quoi et quand, facilitant la documentation RGPD.
Conclusion
Définir les en‑têtes de sécurité et une CSP stricte à la fois dans Strapi et dans Next.js crée une défense en profondeur contre les attaques XSS, le clickjacking, les fuites de données et le contenu mixte. En utilisant Helmet côté API et next-secure-headers côté front‑end, vous obtenez une configuration concise et maintenable. Coupez le tout avec des vérifications automatiques en CI, des scans CSP réguliers et un journal d’audit immuable (Revisionary) pour rester conforme au RGPD et aux meilleures pratiques du secteur. Mettez en œuvre les étapes ci‑dessus dès aujourd’hui et réduisez la surface d’attaque de votre application web pilotée par un CMS headless.
L’équipe Revisionary
Les développeurs de Revisionary, un plugin d’historique des versions pour Strapi 5. Nous écrivons sur Strapi, le développement web, l’IA et la sécurité des applications.
Cet article a été rédigé avec l'aide d'une IA.