Security Headers — One Line, Twelve Headers
Helmet
Helmet sets the security headers every production app should have. Configure for your needs.
What you'll learn
- Mount helmet()
- Tune CSP for your app
- Recognize each header's job
Helmet is one line that sets a dozen security headers. Take it seriously — these headers stop entire classes of attacks.
Default
npm install helmet import helmet from "helmet";
app.use(helmet()); You now have:
| Header | What it does |
|---|---|
Content-Security-Policy | Restricts what scripts/styles can load |
Strict-Transport-Security | Forces HTTPS for the next 6 months |
X-Content-Type-Options: nosniff | Disables MIME sniffing |
X-Frame-Options: SAMEORIGIN | No iframing your pages |
Referrer-Policy | Less referrer info leaks |
Cross-Origin-Resource-Policy: same-origin | Locks down cross-origin resource loading |
Cross-Origin-Opener-Policy: same-origin | Isolates browsing context |
X-DNS-Prefetch-Control | Disables DNS prefetch |
Origin-Agent-Cluster | Origin-keyed agent clusters |
| … | More — read the docs |
Tuning CSP
The default CSP is strict — it blocks all inline scripts and any external scripts. If your app uses CDN scripts, customize:
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://cdn.jsdelivr.net"],
styleSrc: ["'self'", "https://fonts.googleapis.com", "'unsafe-inline'"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'"],
},
},
})); Start strict, loosen only when you have a specific allowed source.
'unsafe-inline' on styleSrc is common but ideally avoided.
Disable Specific Headers
app.use(helmet({
crossOriginEmbedderPolicy: false, // disable this one
})); Some Helmet headers can break legitimate features (embedding, service workers, third-party iframes). Disable individually rather than dropping Helmet altogether.
HSTS Tuning
Helmet’s HSTS default is 180 days. For real prod, the recommended
is 1 year and preload (submitting to browsers’ built-in list):
app.use(helmet({
strictTransportSecurity: {
maxAge: 31536000,
includeSubDomains: true,
preload: true,
},
})); Only enable HSTS preload after you’re sure every subdomain has working HTTPS. Once preloaded, it’s irreversible for ~12 weeks.
Helmet Doesn’t Cover
- CORS — use the
corsmiddleware - CSRF — use a CSRF token system (next lesson)
- Rate limiting —
express-rate-limit - Authentication — that’s your code
Helmet is one layer of defense. Layer them.
CSRF Protection →