Website Security Headers Explained: The Complete Checklist
Security headers are free, take minutes to add, and most sites ship few or none of them. They won't stop a determined attacker on their own, but they close off entire classes of low-effort attacks - and they're one of the first things a security scan checks.
What Are HTTP Security Headers?
They're response headers your server sends alongside every page that tell the browser to enforce a policy - block inline scripts, refuse to be framed, always upgrade to HTTPS, and so on. The browser does the enforcing; your server just has to declare the rule. That makes them cheap defense in depth: even if something else in your stack has a bug, a good header policy limits what that bug can actually do.
Content-Security-Policy (CSP)
The single highest-leverage header on this list. CSP tells the browser which sources are allowed to load scripts, styles, images, and fonts - which is the main mitigation for cross-site scripting (XSS). A minimal starting policy:
default-src 'self'- only load resources from your own origin by default.script-src 'self'- block inline<script>tags and third-party script injection.
Common pitfall: reaching for 'unsafe-inline' the moment CSP breaks something. That defeats most of the point of having a CSP at all - it re-allows the exact inline-script vector CSP exists to block. Use a nonce or hash for the specific inline script you actually need instead.
Strict-Transport-Security (HSTS)
Tells the browser "always use HTTPS for this domain, never even try plain HTTP again," for the duration set in max-age. This closes the window where a user typing your domain without "https://" could be downgraded to an unencrypted connection by a man-in-the-middle. Add preloadonce you're confident, and you can submit your domain to browsers' built-in preload list so the very first request is never sent over HTTP.
X-Frame-Options / frame-ancestors
Prevents your pages from being loaded inside an <iframe>on someone else's site - the standard defense against clickjacking, where an attacker overlays your real UI under an invisible frame to trick users into clicking things they didn't mean to. DENY is the right default unless you deliberately embed your own pages elsewhere.
X-Content-Type-Options: nosniff
Stops the browser from trying to "guess" a file's type based on its content instead of trusting the declared Content-Type. Without this, a file uploaded as an image but containing HTML/JS can, in some older browser behaviors, get executed as a script. One line, no downside.
Referrer-Policy
Controls how much of your URL gets leaked to other sites when a user clicks a link away from you - by default, the full URL (including query strings, which can contain tokens or IDs) gets sent. strict-origin-when-cross-origin is a sane default: full URL on same-origin navigation, just the origin on cross-origin.
Permissions-Policy
Explicitly disables browser features you don't use - camera, microphone, geolocation. If a third-party script on your page is later compromised, this stops it from being able to request access to hardware your site never needed in the first place.
A Minimal, Safe Starter Set
Here's a reasonable default for a Next.js app - adjust the CSP to match your actual script sources before shipping it:
1// next.config.js
2module.exports = {
3 async headers() {
4 return [
5 {
6 source: "/:path*",
7 headers: [
8 { key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
9 { key: "X-Content-Type-Options", value: "nosniff" },
10 { key: "X-Frame-Options", value: "DENY" },
11 { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
12 { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
13 {
14 key: "Content-Security-Policy",
15 value: "default-src 'self'; img-src 'self' data: https:; script-src 'self'",
16 },
17 ],
18 },
19 ];
20 },
21};Checking Your Own Headers
Open your browser's devtools, go to the Network tab, click your page's main request, and look at Response Headers - or just run a scan and get every header, cookie flag, and TLS misconfiguration checked in one pass instead of going header-by-header by hand.
Find out which headers you're missing
Run a free security scan and get a plain-English breakdown of every header, cert, and exposed secret.
Run a free security scan