Headers HTTP & Helmet
Sécurisez vos réponses HTTP avec les headers essentiels et automatisez-les avec Helmet.js.
01 Les headers de sécurité HTTP essentiels
Les headers HTTP de sécurité sont des directives envoyées par le serveur dans chaque réponse. Ils instruisent le navigateur sur la manière de traiter le contenu, réduisant la surface d'attaque côté client.
| Header | Rôle | Sans lui |
|---|---|---|
Content-Security-Policy | Contrôle les sources autorisées (scripts, styles, images…) | XSS possible |
Strict-Transport-Security | Force HTTPS, mémorise la décision | Downgrade HTTP |
X-Frame-Options | Empêche l'affichage dans une iframe | Clickjacking |
X-Content-Type-Options | Empêche le MIME sniffing | MIME confusion |
Referrer-Policy | Contrôle l'URL envoyée dans l'en-tête Referer | Fuite URL |
Permissions-Policy | Restreint l'accès aux API navigateur (caméra, géoloc…) | Abus API |
02 Helmet.js — automatisation des headers
Helmet est un middleware Express qui configure automatiquement 11+ headers de sécurité en une seule ligne. C'est la première chose à ajouter sur tout projet Node.js.
const express = require('express'); const helmet = require('helmet'); const app = express(); // Active tous les middlewares Helmet par défaut app.use(helmet()); // Ou personnalisé : app.use(helmet({ contentSecurityPolicy: { directives: { "default-src": ["'self'"], "script-src": ["'self'", "https://cdn.jsdelivr.net"], "img-src": ["'self'", "data:"], } }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true } }));
Middlewares activés par défaut
| Middleware Helmet | Header configuré | Valeur par défaut |
|---|---|---|
contentSecurityPolicy | Content-Security-Policy | Politique restrictive |
hsts | Strict-Transport-Security | max-age=15552000 |
frameguard | X-Frame-Options | SAMEORIGIN |
noSniff | X-Content-Type-Options | nosniff |
referrerPolicy | Referrer-Policy | no-referrer |
xssFilter | X-XSS-Protection | 0 (désactivé, CSP suffit) |
dnsPrefetchControl | X-DNS-Prefetch-Control | off |
permittedCrossDomainPolicies | X-Permitted-Cross-Domain-Policies | none |
hidePoweredBy | X-Powered-By | Supprimé |
ieNoOpen | X-Download-Options | noopen |
originAgentCluster | Origin-Agent-Cluster | ?1 |
03 Content-Security-Policy — directives, nonces, hashes
La CSP est le header le plus puissant pour contrer le XSS. Elle déclare une liste blanche des sources autorisées pour chaque type de ressource.
Directives essentielles
// Politique stricte pour une SPA React Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://images.example.com; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';
Nonce vs Hash
| Technique | Usage | Exemple |
|---|---|---|
| Nonce | Script inline dynamique — token unique par requête | script-src 'nonce-{random}' |
| Hash | Script inline statique — hash SHA256 du contenu | script-src 'sha256-abc...' |
| 'unsafe-inline' | Autorise tous les scripts inline — à éviter | Dangereux |
// Générer un nonce côté serveur (Express) const crypto = require('crypto'); app.use((req, res, next) => { res.locals.nonce = crypto.randomBytes(16).toString('base64'); next(); }); // Dans le template EJS : // <script nonce="<%= nonce %>"> ... </script>
04 HSTS — Strict-Transport-Security
HSTS force le navigateur à utiliser HTTPS pour toutes les futures requêtes vers un domaine, même si l'utilisateur tape http://. La directive max-age définit la durée de mémorisation en secondes.
// Header optimal Strict-Transport-Security: max-age=31536000; includeSubDomains; preload // Avec Helmet : helmet({ hsts: { maxAge: 31536000, // 1 an en secondes includeSubDomains: true, // Couvre *.example.com preload: true // Permet l'inclusion dans le navigateur preload list } })
HSTS Preloading
Le preloading inscrit votre domaine dans une liste embarquée dans Chrome, Firefox, Safari. Même la toute première requête HTTP est refusée par le navigateur. Pour s'inscrire : hstspreload.org.
05 X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy
X-Frame-Options
Empêche le chargement de votre page dans une <iframe>, bloquant le clickjacking.
X-Frame-Options: DENY // Aucune iframe autorisée X-Frame-Options: SAMEORIGIN // Iframe autorisée sur le même domaine seulement // Note : frame-ancestors dans CSP est plus flexible et moderne Content-Security-Policy: frame-ancestors 'self' https://admin.example.com;
X-Content-Type-Options
Empêche le navigateur de deviner (sniff) le Content-Type d'une réponse. Sans ce header, un fichier texte uploadé peut être interprété comme JavaScript.
X-Content-Type-Options: nosniff // Seule valeur valideReferrer-Policy
Contrôle quelles informations sont incluses dans l'en-tête Referer des requêtes sortantes.
| Valeur | Comportement |
|---|---|
no-referrer | Jamais d'info envoyée |
strict-origin | Envoie seulement l'origine (domaine), pas le chemin |
strict-origin-when-cross-origin | Chemin complet intra-site, domaine seul cross-site |
unsafe-url | Tout envoyer — dangereux |
Permissions-Policy
Remplace l'ancien Feature-Policy. Restreint l'accès aux fonctionnalités navigateur pour votre page et les iframes embarquées.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=() // Désactive caméra, micro, géolocalisation et paiement pour toutes les origines // Avec Helmet : helmet({ permissionsPolicy: { features: { camera: [""], microphone: [""], geolocation: [""], } } })