The Complete Guide to HTTP Security Headers in 2026
HTTP security headers are the cheapest security win available to any website. They're a handful of lines in your web-server config, they take an afternoon to set up, and they defend against whole classes of attack — cross-site scripting, clickjacking, protocol downgrades, MIME sniffing, data leakage through referrers. Yet most production sites ship few or none of them, usually because nobody is sure which headers matter, what each one actually does, or what a safe starting value looks like.
This guide covers every security header worth setting in 2026, in priority order, with copy-paste configs for nginx, Apache and Caddy at the end.
How security headers work
Every HTTP response your server sends can carry instructions to the browser: don't run scripts from unknown origins, never load this site over plain HTTP, refuse to render this page inside a frame. The browser enforces them on the user's machine — which is exactly where attacks like XSS and clickjacking play out. Your server-side code never sees the attack; the browser simply refuses to cooperate with it.
That's also why headers must be set on every response, including error pages and redirects. A 404 page without your headers is an unprotected page.
The headers, in priority order
1. Strict-Transport-Security (HSTS)
Strict-Transport-Security: max-age=31536000; includeSubDomains
HSTS tells the browser to refuse plain-HTTP connections to your domain for max-age seconds — every future request is upgraded to HTTPS before it leaves the machine, and certificate errors become non-bypassable. It closes the window where a first http:// request can be intercepted and downgraded.
Don't paste a one-year max-age with includeSubDomains on day one: if any subdomain still needs HTTP, you've just broken it for a year. Start small and ramp up — the full strategy (and the near-irreversible preload list) is covered in our HSTS deep dive.
2. Content-Security-Policy (CSP)
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
CSP is the most powerful header on this list: an allowlist that controls where scripts, styles, images and frames may load from. A good script-src is the strongest browser-side defence against XSS that exists.
It's also the only header here that can break your site if you get it wrong, which is why you should always start in Content-Security-Policy-Report-Only mode and tighten from there. We've written a full practical CSP guide with ready-to-adapt policies — read it before enforcing anything.
3. X-Content-Type-Options
X-Content-Type-Options: nosniff
The easiest win on the list. Without it, browsers may "sniff" a response's content and second-guess your declared Content-Type — historically letting an attacker get a harmless-looking upload interpreted as script. nosniff disables that guessing. There is exactly one valid value and essentially no way for it to break a correctly configured site. Set it everywhere.
4. X-Frame-Options and frame-ancestors
X-Frame-Options: DENY
This blocks other sites from embedding yours in an <iframe> — the mechanism behind clickjacking, where an invisible copy of your UI is layered over a decoy page so users click your buttons without knowing. The modern replacement is CSP's frame-ancestors directive, which supersedes X-Frame-Options in browsers that support it; sending both covers everything. See the full clickjacking walkthrough for when you legitimately need framing and how to allow it safely.
5. Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Controls what the Referer header leaks when users click away from your site. Without a policy, full URLs — including path and query string, which often contain tokens, search terms or account identifiers — can be sent to third-party sites. strict-origin-when-cross-origin (the modern browser default, but worth setting explicitly) sends the full URL on same-origin navigation, only your origin cross-origin, and nothing at all when going from HTTPS to HTTP.
6. Permissions-Policy
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Declares which browser features your site (and any embedded frames) may use. If you don't use the camera, microphone or geolocation APIs, turn them off: it means an injected script or a compromised third-party embed can't quietly ask for them either. Empty parentheses mean "no one, including us." Add only the features you actually use, e.g. geolocation=(self).
7. Cross-origin isolation: COOP, COEP, CORP
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
These newer headers control how your site interacts with cross-origin windows and resources:
- COOP (
Cross-Origin-Opener-Policy) severs thewindow.openerrelationship between your pages and cross-origin windows, blocking a class of cross-window attacks and tab-nabbing tricks. - CORP (
Cross-Origin-Resource-Policy) declares who may load a given resource, protecting your assets from being read cross-origin. - COEP (
Cross-Origin-Embedder-Policy) requires every subresource to opt in via CORP or CORS. Combined with COOP it unlocks "cross-origin isolated" mode — required forSharedArrayBufferand high-resolution timers.
COOP and CORP same-origin are safe for most sites. Be careful with COEP: it will block any embedded third-party resource that hasn't opted in, so treat it like CSP — test before enforcing. If you're unsure, ship COOP and CORP now and defer COEP.
8. Cookie flags
Not response headers in the same sense, but part of the same audit: every session cookie should carry Secure, HttpOnly and an explicit SameSite attribute. These are set by your application, not your web server, and they're a big enough topic that we've covered them separately in the cookie security guide.
Retired headers you can drop
X-XSS-Protection is obsolete — the auditor it controlled has been removed from modern browsers, and setting it to 1 could even introduce vulnerabilities in old ones. If you set it at all, X-XSS-Protection: 0 is the defensible value; CSP is the real replacement. Expect-CT is likewise obsolete now that Certificate Transparency is enforced by default.
Copy-paste: nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;
The always flag matters — without it nginx drops the headers on 4xx/5xx responses. Note that add_header directives are not inherited if a nested block declares its own add_header; keep them all at one level. Add CSP once you've tested it in report-only mode.
Copy-paste: Apache
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
Header always set Cross-Origin-Opener-Policy "same-origin"
Header always set Cross-Origin-Resource-Policy "same-origin"
Requires mod_headers (a2enmod headers on Debian/Ubuntu). Place in the virtual host, or .htaccess if that's all you control.
Copy-paste: Caddy
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Resource-Policy "same-origin"
}
Caddy provisions HTTPS automatically but does not set these hardening headers for you.
A sane rollout order
- Today, zero risk:
X-Content-Type-Options,Referrer-Policy,X-Frame-Options(if nothing legitimately frames you). - This week, minimal testing: HSTS with a short
max-age,Permissions-Policy, COOP and CORP. - This month, in report-only first: CSP, then ramp HSTS toward a year.
- When ready: COEP, cookie-flag audit, HSTS preload.
Set once, then watch it
The failure mode with security headers isn't getting them wrong once — it's silent regression. A config refactor, a new reverse proxy, a CDN migration, and a header quietly disappears with no error anywhere. That's why CompleteStatus doesn't just check your headers once: it grades them A+ to F continuously, hands you the exact remediation snippet for each finding, and alerts you the moment the grade drops.
See where you stand right now with the free security header checker — instant grade, no signup. Then start monitoring free to catch regressions automatically. The free tier allows commercial use.