Skip to main content

HTTP security headers

Type: ExplanationCreated: Team: Security
draft

Overview​

When a browser loads a web page, the server returns the content plus a set of response headers — instructions that tell the browser how to behave. Security headers are the subset of those instructions that harden the browser's behavior: e.g. "only connect over HTTPS," "don't let other sites frame me," "don't guess file types."

Why they matter​

Security headers are passive defenses. They cost nothing to send, are invisible to users, and replace the browser's permissive defaults with safer ones. On their own, a missing header is rarely directly exploitable — the value appears when another weakness exists. The right headers shrink the blast radius: they can turn an XSS bug into a contained issue instead of full session theft, block clickjacking, and stop protocol downgrades. They're defense-in-depth, not a primary control.

The common headers​

HeaderDefends againstTypical value
Strict-Transport-Security (HSTS)TLS downgrade / SSL-stripmax-age=31536000; includeSubDomains; preload
Content-Security-Policy (CSP)XSS, data injectiondefault-src 'self'; object-src 'none'; frame-ancestors 'none' (tailored per app)
X-Frame-OptionsClickjackingDENY (or SAMEORIGIN)
X-Content-Type-OptionsMIME-sniffingnosniff
Referrer-PolicyURL/token leakage via Refererstrict-origin-when-cross-origin
Permissions-PolicyUnwanted use of browser featurescamera=(), microphone=(), geolocation=()
Cross-Origin-Opener-Policy (COOP)Tab-takeover via window.opensame-origin
Cross-Origin-Resource-Policy (CORP)Cross-site reads of resourcessame-origin or same-site
Cross-Origin-Embedder-Policy (COEP)Spectre-class side-channelsrequire-corp
Clear-Site-DataStale data on shared devices"cache", "cookies", "storage" (logout only)
Content-TypeResponse-type confusionapplication/json; charset=utf-8 (on JSON)

The "easy" ones vs. the ones that need care​

Most of these are safe to deploy with the standard value and rarely break anything: X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, COOP, CORP. The four below need thought:

  • HSTS — hard to reverse. Once a browser sees it, it refuses HTTP for the whole max-age, and preload is effectively permanent. Verify HTTPS works everywhere first; start with a short max-age; only submit to the preload list once you're certain. With includeSubDomains, any non-HTTPS subdomain becomes unreachable.
  • CSP — the strongest header but the highest-maintenance. A strict script-src allowlist must be updated whenever a new third-party script is added. Always roll out in Content-Security-Policy-Report-Only mode first, collect violations, then enforce. Apps with many third-party scripts often accept a looser policy or stay in report-only.
  • COEP (require-corp) — only needed for cross-origin isolation features (SharedArrayBuffer, high-res timers). It forces every cross-origin resource to opt in or be blocked, which breaks fonts/images/scripts on most sites. Usually skipped unless specifically required.
  • Clear-Site-Data — the "cookies" directive clears cookies for the entire registered domain and all subdomains, and "storage" only clears the responding origin. On multi-subdomain or split frontend/API setups it often clears the wrong thing or too much, so it needs careful, logout-only scoping — or is skipped.

Where to set them​

They can be set at the application layer, but it's usually cleanest to set them at the CDN / edge (e.g. Cloudflare, CloudFront) so every response is covered without code changes. The two exceptions: Content-Type belongs in the app (the app knows each response's real type), and Clear-Site-Data must be scoped to the logout response only.

How to verify​

  • securityheaders.com and Mozilla / MDN Observatory — give a letter grade and flag missing headers. Target at least an A.
  • Raw check (curl/PowerShell) — the only way to confirm all headers by name, since the graders only score a subset.

Note: no single online grader checks every header above. securityheaders.com and Observatory score the high-impact subset; the full list is best confirmed with a direct header dump.