Most web apps ship with a response that quietly leaks attack surface. No Content-Security-Policy, a chatty Server header, framing wide open. None of it shows up in a demo, so it survives to production. This is the exact checklist I run to take a site from an F to an A+ — and why each header earns its place.
Try it live: the Security Toolkit on this site scans any URL and grades its headers the same way.
The headers that matter
Content-Security-Policy
The single strongest defense against XSS. It tells the browser which sources are allowed to load scripts, styles, images, and more. Start in report-only mode so you don't break the app while you tune it:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'
Once the violation reports are clean, drop -Report-Only and enforce. Avoid unsafe-inline on script-src — it's the loophole that makes most CSPs decorative.
Strict-Transport-Security
Forces HTTPS for a set duration and blocks protocol-downgrade attacks. Once you're confident in your certs:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
The supporting cast
- X-Frame-Options: DENY — kills clickjacking by refusing to be framed.
- X-Content-Type-Options: nosniff — stops MIME sniffing that can turn an upload into a script.
- Referrer-Policy: strict-origin-when-cross-origin — stops full URLs (with tokens) leaking to third parties.
- Permissions-Policy — disables powerful APIs you don't use:
geolocation=(), camera=(), microphone=().
Applying it in Next.js
Set them once in next.config.mjs and every route inherits them:
const securityHeaders = [
{ 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" }
];
export default {
async headers() {
return [{ source: "/:path*", headers: securityHeaders }];
}
};
The mindset
Security headers are cheap insurance: a few lines of config that shrink your attack surface before an attacker ever probes it. Scan your own site, fix the reds, and re-scan. Defense should be measurable — a letter grade you can point to, not a vibe.