Six headers to set
| Header | Protects | Recommended |
|---|---|---|
| Strict-Transport-Security | Forces HTTPS, stops downgrade | max-age=31536000; includeSubDomains; preload |
| Content-Security-Policy | Limits loadable resources, blocks XSS | Tighten gradually per app |
| X-Content-Type-Options | Stops MIME sniffing | nosniff |
| X-Frame-Options / frame-ancestors | Stops clickjacking | DENY or SAMEORIGIN |
| Referrer-Policy | Limits referrer leakage | strict-origin-when-cross-origin |
| Permissions-Policy | Revokes unneeded browser power | Disable camera/mic as needed |
Don't write CSP in one shot
Start with Content-Security-Policy-Report-Only to catch false positives, then switch to enforcing. Prefer a nonce or hash over unsafe-inline, and list external script domains explicitly.
Two common mistakes
- HSTS is hard to undo: with
includeSubDomains+preload, subdomains are locked out of HTTP for a long time — confirm every subdomain supports HTTPS first; - Set only at the edge: if the CDN adds the header but the origin doesn't, an attacker hitting the origin bypasses it. Set it at both layers.
How to verify
Run curl -I https://your-domain to read response headers, or use an online header scan. Make sure core flows work before tightening.
Real-world cases: three integrations blocked by security headers
- An iframe embedding goes blank: the site sends
X-Frame-Options: DENY, so a partner's embed shows nothing. If embedding is genuinely needed, switch to CSPframe-ancestorslisting the allowed origins. - A CDN script blocked by CSP:
Content-Security-Policywas added butscript-srcomits the CDN domain, breaking page functionality. Roll CSP out withContent-Security-Policy-Report-Onlyfirst, then enforce. - HSTS locking down a test domain:
Strict-Transport-SecuritywithincludeSubDomainson a wildcard domain where a test subdomain lacks HTTPS leaves browsers refusing downgrades for a long time. Confirm every subdomain supports HTTPS first.
FAQ
Where should security headers be set? At the edge (CDN or gateway) so no service forgets, though CSP usually needs per-app tuning. What is X-Content-Type-Options for? It stops browsers sniffing content types and executing an uploaded text file as a script. Does CSP prevent XSS? It substantially reduces risk but does not replace output escaping and input validation. Which Referrer-Policy? strict-origin-when-cross-origin — full referrer same-origin, origin only cross-origin.
Rolling out CSP in stages
A misconfigured CSP breaks pages instantly, so phase it in:
- Start with Report-Only: use
Content-Security-Policy-Report-Onlyto observe real violations for a week or two without blocking; - Collect reports: configure
report-to/report-uriand analyse centrally, separating inline scripts you must fix from third-party resources; - Eliminate inline scripts: move them to files or use nonces — leaving
unsafe-inlinein place sharply reduces CSP's XSS value; - Tighten directives gradually: lock down
default-srcandscript-srcfirst, then addimg-src,connect-srcandframe-ancestors; - Enforce last: switch to enforcing once violation reports are clear, keeping a rollback switch.
The minimum header set is Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy and Permissions-Policy. Put them on the deployment checklist and inject at the platform level rather than per service.
From audit to routine practice
Security headers pay off through long-term consistency, not a single tidy configuration.
- Start with a baseline scan: use a scanner or online check to list missing or misconfigured headers, ordered by impact, instead of changing everything at once.
- Codify into deployment templates: put header configuration in infrastructure code or the gateway so the platform injects it and new services cannot forget it. Manually editing each server does not survive.
- Add a regression check: validate in the release pipeline that key headers exist with expected values, or a refactor will quietly drop them.
- Review the policy periodically: browser standards and business dependencies change; revisit every six months and consider tightening.
- Record exceptions: any relaxation made for compatibility needs a reason, an owner and an expiry date, or temporary compromises become permanent holes.
With all five, headers become a controlled routine rather than a one-off task, and you can produce evidence for audits.