Web Security
One small app, attacked and fixed.
This track follows one small web application, a notes service with accounts, from its first naive version to a hardened one. It runs locally, with a real browser driving it, so every attack shown actually ran and every fix was checked against the attack it is meant to stop.
Each chapter starts from a hole the previous one left open. The browser’s rule about origins explains why a page can’t simply read another site’s data, and also why it can still make the browser send requests there. Cookies carry the session, and that makes forged requests possible. Escaping output stops one kind of injected script, and the ones that remain lead to Content Security Policy. Further on, the attacks move to the server: input that becomes a query or a command, a server tricked into fetching for the attacker, users reaching data that isn’t theirs. The last chapters cover the connection and the domain the app is served from, and the code it depends on but didn’t write.
Login tokens, OAuth and sessions are covered in depth in the essay on JWTs, OAuth and Zero Trust, and the System Design security chapter covers the system-level view. This track stays close to the browser and the request.
Chapters
- 1Where the browser draws linesThe notes app's first version, and the browser's rules about origins and sites: what another site can make the browser send, and what it can never read back.Draft
- 2Cookies and sessionsThe session cookie under attack: who can read it, where it travels, how a planted cookie becomes someone's login, and what HttpOnly, Secure, SameSite, the __Host- prefix and session rotation each change, measured in Chrome.Draft
- 3Forged requestsCross-site request forgery against the notes app: what SameSite=Lax stops and what it lets through, synchronizer and double-submit tokens, Fetch Metadata checks, and login CSRF, each attack run in Chrome before and after its fix.Draft
- 4Script that isn't yoursCross-site scripting against the notes app: stored, reflected and DOM-based, why escaping depends on where the text lands, where Jinja2's autoescaping stops helping, HTML sanitization, and what an injected script does with a session it can't read.Draft
- 5Content Security PolicyContent Security Policy as a second line behind output encoding: why host allowlists fail, nonce-based policies with strict-dynamic, object-src and base-uri, report-only rollout and violation reports, and Trusted Types, each run against chapter 4's attacks in Chrome.Draft
- 6Asking across originsCross-Origin Resource Sharing on the notes app's JSON API: what the browser sends and what it lets a page read, simple and preflighted requests, credentials, the misconfigurations that hand the API to any site (reflected Origin, null, suffix matching), and the older cross-origin channels, JSONP and postMessage.Draft
- 7Frames and headersThe rest of the browser's defenses, each switched on by a response header: clickjacking and frame-ancestors, HSTS, nosniff, Referrer-Policy, Permissions-Policy, and COOP, CORP and COEP after Spectre, measured in Chrome before and after.Draft
- 8When input becomes codeServer-side injection on the notes app, each run for real: SQL injection in PostgreSQL through a search box, a sort order and a username, then command injection, path traversal, template injection and an unpickled cookie.Draft
- 9The server fetches for youServer-side request forgery through the avatar-from-URL feature: reaching an internal admin service and a simulated cloud metadata endpoint, beating blocklists with encoded addresses, redirects and DNS rebinding, then a fetcher that resolves, pins and rechecks; XXE briefly.Draft
- 10Whose data is it?Broken access control on the notes app: reading other users' notes by changing an ID, making yourself admin with one JSON field, admin APIs nobody guarded, account enumeration by message and by timing, login throttling and password reset.Draft
- 11The connection and the domainWhat TLS gives the app and what it doesn't: certificate chains and ACME, HSTS and preload, mixed content in Chrome, CAA records, certificate transparency, DNSSEC, and a subdomain taken over through a dangling DNS record.Draft
- 12Code you didn't writeThe code the app runs but nobody on the team wrote: pinned and hashed dependencies, a look-alike package winning an install, install scripts, Subresource Integrity in Chrome, provenance, secrets left in git history, CI permissions, and the OWASP Top 10 as a map back over the track.Draft