Security Headers & CSP
Problème
Les applications web sont vulnérables au XSS, clickjacking, MIME sniffing et downgrade attacks faute de headers de sécurité.
Solution
Defense-in-depth via HTTP response headers. Une structure "safe even if you slip" plutôt que "dangerous if you slip".
Headers obligatoires
HSTS (HTTP Strict Transport Security)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- Force HTTPS, empêche downgrade attacks
preloadpour soumission à la HSTS preload list
CSP (Content-Security-Policy)
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{RANDOM}'; style-src 'self' 'nonce-{RANDOM}'; img-src 'self' data: https:; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
default-src 'self'— deny by defaultnonce-{RANDOM}— autorise seulement les scripts avec le nonce (généré par request)frame-ancestors 'none'— empêche clickjacking (remplace X-Frame-Options)- Pas de
'unsafe-inline'ni'unsafe-eval'
Autres headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
Implementation Express.js (Helmet)
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'nonce-{RANDOM}'],
styleSrc: ["'self'", 'nonce-{RANDOM}'],
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'", 'https://api.example.com'],
frameAncestors: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"]
}
},
strictTransportSecurity: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
Implementation Next.js
// next.config.js
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}';
style-src 'self' 'nonce-${nonce}';
img-src 'self' data: https:;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
`
module.exports = {
async headers() {
return [{
source: '/(.*)',
headers: [
{ key: 'Content-Security-Policy', value: cspHeader },
{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains; preload' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'geolocation=(), microphone=(), camera=()' }
]
}]
}
}
Vérification
- Mozilla Observatory — score A+ visé
- securityheaders.com
Références
- [[KNOW-REF-043]] — OWASP ASVS V13 (security headers)
- [[KNOW-REF-044]] — OWASP Proactive Controls C8
- [[KNOW-PAT-220]] — Secure SDLC Checklist