You're viewing the readable version of this site. The interactive extras (search, diagrams, read-aloud) need JavaScript and a current browser. Enable JavaScript; if it is already enabled, update your browser.

Series

The Web Security series

16 pieces, in order — a web security series.

The Web Security series, read in order. Part of Dissecting Real Systems.

  1. Code From Strangers — A map of web security before the deep dives — one asymmetry that explains every attack, five questions the mechanisms answer, and the vocabulary you need so none of the rest reads as noise.
  2. Trust No Script — Why a strict Content Security Policy is one of the hardest headers to deploy — and how to read one with Google's CSP Evaluator.
  3. The Header That Can't Be Cached — Cache-Control from first principles — and why a page carrying a CSP nonce must be told never to be stored, not merely "don't cache."
  4. Can I Use This Library? — A strict CSP quietly turns every dependency into a security decision. Here is the tree I walk to make it — per library, and across a whole app.
  5. Where Did This Request Come From? — The Sec-Fetch-Site, -Mode, -Dest and -User headers answer a question servers could never ask — and turn a class of cross-site attacks into a four-line check.
  6. Don't Write the Policy. Derive It. — A security policy is a claim about every case you did not think of. State the invariant instead, enumerate what the system can actually do, and let a model checker hand you the counterexample.
  7. HSTS: It's Time to Go HTTPS-Only — The header that makes HTTPS non-negotiable — no SSL stripping, no click-through, no fast rollback. Turn it on. Then think carefully before you preload, because that part you cannot take back.
  8. Nobody Shares Your Address Space — COOP, COEP and CORP are presented as three related headers. They are three doors into one process — and Spectre is why the browser cares who is inside it, not just what they are allowed to read.
  9. The URL Is the Hash — Content-addressing on the wire — how the web quietly became a content-addressed store, where fingerprinted URLs and Subresource Integrity are real Merkle edges and the cache that looks most like one isn't.
  10. Two Parsers Walk Into a DOM — Every HTML sanitizer is a second implementation of a parser it does not control. Mutation XSS is what happens in the gap — and it is why the fix eventually had to move inside the browser.
  11. Strings Do Not Remember Where They Came From — Trusted Types does not make XSS impossible — the spec says so itself. It makes unreviewed assignment impossible, which is a smaller claim and a far more useful one.
  12. The Header That Grants Nothing — CORS does not protect your server. It relaxes a rule about who may read a reply — and almost every misconfiguration comes from believing it does the opposite.
  13. The Credential That Predates the Origin — Cookies do not obey the same-origin policy — they never have. Thirty years of attributes, flags and name prefixes are one long retrofit, and knowing which parts actually hold is most of session security.
  14. One Defect, Three Surfaces — CORS allowlists, OAuth redirect URIs and open redirects have separate vulnerability literatures and the same bug — a structured identifier tested with a string operation. The fix is one sentence, and a standards body finally wrote it down.
  15. Four Hundred Findings — A scanner report is not a list of your vulnerabilities. It is a list of your dependencies crossed with a database — and about one in thirty is reachable from code you actually run.
  16. Why Your Progressive Approach to Web Security Fails — Adding a security header can only tighten what reaches the browser; nothing you add can loosen it. Loosening is a hand edit of the policy already shipped — and that asymmetry is why incremental hardening degenerates into permissive sprawl, and why deny-by-default with a report-only rollout is the only shape that survives a real application.