Security Headers — The Browser's Perspective

Chapter 6
Security Headers — The Browser's Perspective
CSP, HSTS, and X-Frame-Options — what each header actually tells the browser to refuse to do

The earlier "Securing Your Web Server" course covered these same headers from the server-configuration side — what to put in your Apache config. This chapter covers the same headers from the other end: what the browser actually does once it receives them, and why each one closes a specific, real attack rather than being generic best-practice advice.

Content-Security-Policy (CSP) — Restricting What a Page Can Load and Run

CSP tells the browser exactly which sources are allowed to provide scripts, styles, images, fonts, and other resources for a page — anything not explicitly allowed is simply blocked from loading or executing, no matter what HTML or JavaScript tries to request it.

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data:;
DirectiveControls
default-srcFallback for any resource type not given its own directive
script-srcWhere JavaScript is allowed to load from — the most security-critical directive
style-srcWhere CSS is allowed to load from
img-srcWhere images are allowed to load from
connect-srcWhich origins fetch/XMLHttpRequest/WebSocket can connect to — directly relevant to Chapter 5's CORS coverage
frame-ancestorsWhich sites are allowed to embed this page in an iframe — the modern replacement for X-Frame-Options, covered below

'self' means "only this exact origin" (Chapter 5's definition of origin applies directly here). A strict CSP is one of the most effective defences against cross-site scripting (XSS) — even if an attacker manages to inject a <script> tag pointing at their own domain, a correctly configured script-src simply refuses to execute it.

CSP violations show up in the console, and can be reported without blocking anything
Content-Security-Policy-Report-Only applies the same policy but only logs violations to the console (and optionally a reporting endpoint) without actually blocking anything — the standard way to test a new policy against real traffic before switching it to enforcing mode.

HSTS — Forcing HTTPS for Every Future Visit

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Once a browser receives this header from a site, it remembers (for the given max-age, here one year) to never attempt an HTTP connection to that domain again — even if a user explicitly types http:// or clicks an old http link, the browser silently rewrites it to https before ever sending a request.

Without HSTS
A user typing or clicking an http:// link makes one real (insecure) request to the server before any redirect to HTTPS can happen — that single request is interceptable on an untrusted network.
Vulnerable to: SSL-stripping attacks on the first connection
With HSTS
After the first HTTPS visit, the browser enforces HTTPS internally — no insecure request is ever sent again for that domain, closing the exact window the attack above relies on.
Protects: every subsequent visit, automatically
includeSubDomains and preload are commitments, not casual flags
includeSubDomains applies HSTS to every subdomain too — meaning every subdomain must have valid HTTPS working, or they become entirely unreachable. preload submits the domain to a hardcoded list baked into browsers themselves, applying HSTS from a user's very first visit ever — genuinely difficult to reverse once submitted. Both are worth using deliberately, not by default, on a domain you're fully confident will keep working HTTPS indefinitely.

X-Frame-Options and frame-ancestors — Controlling Embedding

X-Frame-Options: SAMEORIGIN
// Modern equivalent, more flexible, part of CSP:
Content-Security-Policy: frame-ancestors 'self';

These headers control whether another site can embed your page inside an <iframe> — without this restriction, an attacker can layer invisible iframes of your real site under deceptive buttons on their own page, tricking a logged-in user into clicking something on your site without realising it (a technique called clickjacking).

DENY
No site, including your own, can embed this page in a frame at all.
SAMEORIGIN
Only the exact same origin (Chapter 5's definition) can embed it — your own site can, nobody else can.
frame-ancestors (CSP)
The modern, more flexible replacement — can specify a list of explicitly trusted origins allowed to embed the page, not just same-origin-or-nothing.

Checking What's Actually Configured

Browser DevTools → Network tab → click any request → Response Headers shows exactly which of these headers a site is actually sending — the fastest way to verify a server configuration change actually took effect, without guessing.

Online header-scanning tools exist for a quick external check
Several free online security-header scanners exist that fetch a URL and grade which of these headers are present and correctly configured — useful for a quick sanity check after deploying a configuration change, complementing the manual DevTools inspection above.

Chapter 6 Quick Reference

  • CSP — whitelists allowed sources for scripts/styles/images/connections; the main defence against XSS at the browser level
  • Content-Security-Policy-Report-Only — test a policy's violations without enforcing it yet
  • HSTS — forces HTTPS for all future visits to a domain, closing the SSL-stripping window on a user's first connection
  • includeSubDomains / preload — powerful but hard-to-reverse HSTS extensions; use deliberately
  • X-Frame-Options / frame-ancestors — controls iframe embedding, the main defence against clickjacking
  • Check headers via DevTools Network tab — Response Headers on any request
  • Next chapter: session & auth tokens — cookies vs JWT vs server sessions, and where to safely store what