Security Headers and Defenses
A handful of HTTP response headers instruct the browser to enforce protections the server cannot enforce alone — forcing HTTPS, restricting scripts, controlling framing, and limiting what data leaks across origins. They are cheap to add and catch whole classes of attack as defense in depth, but they are precise: a wrong CSP breaks the app, a missing HSTS leaves a downgrade path.
This topic covers the headers worth setting on app.meridian.example and what each actually prevents — layered defense over correct code, not a substitute for it.
HSTS — Forcing HTTPS
Strict-Transport-Security tells browsers to only ever use HTTPS for the site, closing the downgrade and stripping gap from Chapter 2. With preloading, even the very first request is protected, because the browser knows to use HTTPS before it ever contacts the site. This is what makes "redirect to HTTPS" actually stick.
Content Security Policy
CSP is the strongest anti-XSS backstop: a whitelist of where scripts, styles, and connections may come from, so injected script has nowhere to run and nowhere to exfiltrate to. It is also the hardest header to author without breaking the app, which is why you roll it out in report-only mode first — collecting violations without enforcing — then tighten and enforce once the legitimate sources are known.
Framing and Referrer Controls
X-Frame-Options or CSP's frame-ancestors stop other sites from framing yours to trick clicks (clickjacking) — a one-line header that closes an attack most teams forget. Referrer-Policy stops leaking full URLs, and any tokens in them, to third parties, and Permissions-Policy disables browser features the app does not use.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none' X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: geolocation=(), microphone=(), camera=() # roll CSP out as Content-Security-Policy-Report-Only first, fix violations, then enforce
This set forces HTTPS with HSTS, confines scripts and framing with a strict CSP, stops MIME sniffing, trims referrer leakage, and disables unused browser features. The one operational discipline that keeps it from breaking the app is rolling CSP out in report-only mode first: collect the violation reports, authorize the legitimate sources, and only then switch to enforcing.
Headers Are Defense in Depth
Treat headers as layered defense over correct code, never as the primary control. A CSP does not excuse un-encoded output, and HSTS does not excuse a bad TLS configuration — the headers catch what slips through and contain what goes wrong, but the application still has to be right underneath them. Their value is that they are cheap and they fail safe.
- No HSTS, leaving the first-request downgrade open even when the site redirects to HTTPS.
- Enforcing a strict CSP without a report-only shakeout, breaking the app and getting the policy loosened to uselessness.
- Forgetting anti-framing headers and remaining clickjackable, or leaking sensitive URLs via a permissive
Referrer-Policy. - Treating headers as the primary defense rather than defense in depth — a CSP does not excuse un-encoded output.
- Setting a CSP so loose (allowing
unsafe-inlineeverywhere) that it stops containing XSS at all.
- Set HSTS — and preload it once confident — and enforce HTTPS site-wide so headers cannot be stripped.
- Roll out a strict CSP in report-only mode, fix violations, then enforce; keep it tight (
default-src 'self', no inline script). - Add
frame-ancestorsorX-Frame-Options, a restrictiveReferrer-Policy, andPermissions-Policy, and set the secure cookie flags. - Treat headers as layered defense over correct code, and monitor CSP reports as an XSS early-warning signal.
- Scan the deployed site periodically to confirm the headers are present and strict.
Knowledge Check
Why is HSTS needed even when the server already redirects HTTP to HTTPS?
- The first HTTP request is downgradeable; HSTS closes it
- Redirects are slower than serving HTTPS directly
- HSTS encrypts the certificate's private key
- Without HSTS the server cannot present a valid TLS certificate
Why roll out a Content Security Policy in report-only mode first?
- To discover which sources it would break before enforcing
- Report-only mode is more secure than enforcing mode
- CSP cannot be enforced without a report-only period by the spec
- Report-only mode encrypts the page contents
What is the right way to think about security headers?
- Defense in depth — they don't excuse bad code or TLS
- They are the primary defense and replace output encoding
- They only matter for static websites
- A single header can secure the entire application
You got correct