Part II β The Shield Β· Lesson 3.4
Security Headers
In one lineSix response headers that close whole attack classes without touching application code.
Where you've seen itThe server config block that protects every route at once β including the legacy ones nobody has opened in two years.
Diagram
HEADER β WHAT IT BLOCKS
Content-Security-Policy XSS execution, unexpected script origins
Strict-Transport-Security protocol downgrade, cookie sniffing
X-Content-Type-Options MIME sniffing (.txt executed as JS)
Referrer-Policy leaking URLs + tokens to third parties
Permissions-Policy camera/mic/geo abuse by you or your frames
Cross-Origin-Opener-Policy cross-window attacks, enables isolation
Legacy but still seen:
X-Frame-Options clickjacking (superseded by frame-ancestors)CSP ANATOMY β an allowlist for every resource type
Content-Security-Policy:
default-src 'self'; β fallback for everything
script-src 'self' 'nonce-r4nd0m'; β only your JS + nonced inline
style-src 'self' fonts.googleapis.com;
font-src fonts.gstatic.com;
img-src 'self' data: cdn.example.com;
connect-src 'self' api.example.com sentry.io;
frame-ancestors 'none'; β nobody may frame you
base-uri 'self'; β stops <base> hijacking
object-src 'none'; β kills Flash/plugin vectors
β 'unsafe-inline' β allows every injected <script>, defeats the point
β 'unsafe-eval' β re-enables eval() and string setTimeoutROLLOUT WITHOUT BREAKING PRODUCTION
1. Content-Security-Policy-Report-Only + report-uri nothing blocks
2. watch violation reports for a week
3. fix real gaps, allowlist genuine origins
4. flip to Content-Security-Policy now enforcingHow it works
- Set headers at the edge β CDN, load balancer, or server config β so no route can miss them.
- Start CSP in report-only mode; a strict policy shipped blind takes the site down.
- Prefer nonces or hashes over
'unsafe-inline'; a nonce is generated per response and stamped on your own inline scripts. Strict-Transport-Security: max-age=31536000; includeSubDomainsβ then submit to the preload list once you're sure.- Verify with the browser's Security panel or an external header scanner after every deploy.
Trade-offs
| Header | Cost of getting it wrong |
|---|---|
| CSP too strict | Broken third-party widgets, blank pages |
CSP with 'unsafe-inline' | Header present, protection absent |
HSTS preload | Hard to undo β you're committed to HTTPS |
Referrer-Policy: no-referrer | Breaks analytics attribution |
Interview angle
"You ship a CSP and your payment widget stops loading. What now?"
- Read the console violation: it names the directive and the blocked origin.
- Add that specific origin to the specific directive β never widen to
*or add'unsafe-inline'. - Long term, run report-only in staging so violations surface before release, not after.
Recap
- Headers are the highest-leverage security work: config, not code, applied everywhere.
- A CSP containing
'unsafe-inline'is theatre. - Roll out report-only first, then enforce.