The security header checklist, in the order worth doing them
Security header guides tend to list a dozen headers as equally important. They are not. This is the order that buys the most protection per unit of work, based on what each one actually prevents.
1. Strict-Transport-Security
Strict-Transport-Security: max-age=31536000; includeSubDomains
Do this first because it is one line, breaks nothing once you are https-only, and closes an attack that requires no bug on your part. Redirecting http to https is not sufficient — the first plaintext request is interceptable before your redirect arrives.
Add includeSubDomains once every subdomain serves https. Cookies are shared up the
domain tree, so a single plaintext subdomain undermines the parent.
2. X-Content-Type-Options
X-Content-Type-Options: nosniff
One value, no configuration, prevents the browser second-guessing your Content-Type and executing an uploaded file as script. It occasionally surfaces an existing bug where you serve JavaScript or CSS with the wrong type — that is worth knowing about anyway.
3. Frame protection
Content-Security-Policy: frame-ancestors 'none'
Prevents clickjacking. Use CSP frame-ancestors rather than
X-Frame-Options: it supports a list of origins, and browsers that support it ignore
X-Frame-Options anyway. If you need to support genuinely ancient browsers, set both — it is
harmless, and the CSP value wins where both are understood.
Never rely on X-Frame-Options: ALLOW-FROM. No current browser implements it, so a
policy depending on it provides no protection at all.
4. Content-Security-Policy
The highest-value header and by far the most work, which is why it is fourth rather than first — the three above are quick wins you should not delay behind it.
Start report-only. See the CSP guide.
5. Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
This is the modern browser default, so setting it explicitly changes little — but it removes
the dependency on that default and protects against URLs containing tokens or identifiers leaking
to third parties. Watch for unsafe-url, which sends full URLs everywhere.
6. Permissions-Policy
Permissions-Policy: camera=(), microphone=(), geolocation=()
Deny what you do not use. The reason this matters is embedded frames: a third party in your page can prompt for camera access, and the prompt looks like it came from you.
Advice that is now wrong
X-XSS-Protection: 1; mode=block— the auditor this controlled was removed from every browser because it was bypassable and introduced its own vulnerabilities. Set0or remove the header.- Public-Key-Pins (HPKP) — removed from browsers. It made permanent, unrecoverable site outages easy to cause.
X-Frame-Options: ALLOW-FROM— never widely implemented.- Expect-CT — obsolete. Certificate Transparency is now enforced by default.
Where to set them
At the edge, not in application code — a CDN or reverse proxy rule covers every response including static files and error pages, which is exactly where application-level middleware tends to miss. The one exception is CSP with a nonce, which must be generated per response and so has to come from the application.