03 β How the Web Works, and Where It Breaks
Level: Beginner Β· Time: ~15 min Β· Prerequisites: Lesson 2 β Protocols You Must Know
Why this matters
The web is where most attacks are delivered and where most data leaves. A phishing page is a web page, a ransomware loader is a download, an API is a web service with no browser in front of it, and session cookies are the keys to almost every account you hold. If you understand the exact sequence of events between typing a URL and seeing pixels, then every step becomes a place to look for β or place β a control. That understanding is what separates "we have a WAF" from "we know what the WAF cannot see".
The mental model: one request, ten steps
1. You type https://shop.example.com/cart
2. Browser cache β is this already here? any redirect remembered?
3. DNS resolution β stub β recursive resolver β root β .com β example.com's NS
4. TCP connect β three-way handshake to the returned IP on port 443
5. TLS handshake β certificate, key exchange, cipher agreed (Lesson 4)
6. HTTP request β GET /cart Host: shop.example.com Cookie: session=β¦
7. The edge decides β CDN cache? load balancer? WAF rule? reverse proxy?
8. Application runs β authentication, database queries, template rendering
9. HTTP response β status, headers (Set-Cookie, CSP, HSTS), body
10. Browser renders β HTML parsed, subresources fetched, third-party JS runs
Every one of those ten steps has been the direct cause of a real breach. This lesson walks them in order and names the failure at each.
| Step | What it protects | How it fails |
|---|---|---|
| Browser cache | speed, less traffic | stale content, cached secrets on a shared machine |
| DNS | usability | poisoning, hijacked CNAME, lookalike domains |
| TCP connect | transport | interception, blocking, TCP hijacking |
| TLS handshake | confidentiality, authenticity | expired or wrong certificate, weak parameters, a user who clicked through the warning |
| HTTP request | nothing by itself | parameter tampering, header injection, method confusion |
| The edge | availability, some filtering | assumed-but-absent protection; WAF bypassed by encoding |
| The application | business logic | injection, broken access control, IDOR, deserialisation |
| The response | browser behaviour | missing cookie flags, missing CSP, verbose errors, data leaks |
| Rendering | user experience | XSS execution, malicious third-party scripts, mixed content |
HTTP fundamentals
HTTP is a text request and a text response. That is the entire protocol β which is exactly why it is so malleable and so easy to abuse.
GET /cart?id=4471 HTTP/1.1
Host: shop.example.com
User-Agent: Mozilla/5.0 β¦
Cookie: session=8f14e45fceea167a5a36dedd4bea2543
Accept: text/html
| Method | Meaning | Security note |
|---|---|---|
| GET | retrieve | must be safe and idempotent β a GET that changes state is a bug, and crawlers will trigger it |
| POST | submit data | the normal path for forms; CSRF applies unless protected |
| PUT | replace a resource | frequently missing authorisation checks in APIs |
| PATCH | partial update | partially-applied updates leave inconsistent, sometimes privileged state |
| DELETE | remove | fatal if authorisation is checked only in the UI |
| HEAD | like GET, no body | useful for probing; often not logged or rate-limited |
| OPTIONS | what is allowed here | the method behind CORS preflight |
| Status | Family | What it tells a defender |
|---|---|---|
| 2xx | success | flat success codes across a scan can mean everything is allowed |
| 3xx | redirect | an open redirect here is a phishing ingredient |
| 4xx | client error | 401 vs 403 distinguishes "not authenticated" from "authenticated but not allowed"; 404s in volume are directory brute force |
| 5xx | server error | stack traces and SQL errors in a 500 are information disclosure |
The headers that matter
| Header | Set by | Why it exists |
|---|---|---|
Set-Cookie |
server | delivers the session identifier; without HttpOnly JavaScript can read it, without Secure it crosses plain HTTP, without SameSite it rides along on cross-site requests |
Strict-Transport-Security |
server (HSTS) | tells the browser to refuse plain HTTP to this host for the stated period β the only reliable defence against SSL-stripping |
Content-Security-Policy |
server (CSP) | restricts where scripts, styles and frames may come from β the strongest mitigation for XSS |
X-Frame-Options / CSP frame-ancestors |
server | stops other sites framing yours and overlaying fake UI (clickjacking) |
Access-Control-Allow-Origin |
server (CORS) | decides which other origins may read responses; a wildcard or a reflected origin defeats the same-origin policy |
Authorization |
client | carries the bearer token or credentials for an API call β treat every value as a password |
User-Agent |
client | what the client says it is; trivially forged, useful only for telemetry and crude filtering |
State on the web
HTTP is stateless: the server forgets you between requests. Everything that makes you "logged in" is therefore a workaround, and each workaround has its own failure mode.
- Cookie β a name/value pair the browser stores and sends back to that domain. It is the container. It is not, by itself, identity.
- Session β a server-side record of who you are, keyed by a random identifier held in a cookie. The server controls it, so it can be revoked instantly.
- Token β a self-contained credential presented on each request (
Authorization: Bearer β¦). No server-side session store, so revocation is the hard part. - JWT β a token with a specific format: three base64url segments β header, payload, signature. The signature proves the issuer created it; the payload is encoded, not encrypted, so anyone holding it can read it.
| Failure | What it looks like | The fix |
|---|---|---|
| Session fixation | the attacker knows or sets the session ID before you log in, then reuses it afterwards | issue a new session ID on successful authentication; never accept a client-supplied one |
| Cookie theft | XSS reads document.cookie, or the cookie crosses plain HTTP |
HttpOnly, Secure, SameSite=Lax or Strict, short lifetimes, CSP |
| Token leak in a URL | a token in a query string ends up in logs, history and referrers | send credentials in headers only |
| No expiry | a stolen token works for months | short-lived access tokens plus refresh tokens you can revoke |
JWT signed with alg: none |
the library trusts the header and accepts an unsigned token | pin the expected algorithm; never let the token choose it |
| JWT signature not verified | the application decodes the payload and trusts it | verify every signature, on every request, before reading any claim |
| Secrets in the JWT payload | roles, internal IDs or worse, readable by anyone | keep the payload minimal; authorise against server-side data |
[!IMPORTANT] The same-origin policy is the browser's core safety rule: a page from one origin cannot read responses from another origin. CORS is a deliberate, narrow hole in that rule β the server tells the browser which other origins may read its responses. Any configuration that reflects whatever
Originthe caller sends, or allows any origin with credentials, has quietly removed the rule for every site on the internet.
The modern edge
Almost no production request reaches the application server directly.
| Component | What it does | What it does not do |
|---|---|---|
| Reverse proxy | terminates TLS, routes by host or path, normalises requests | authorise anything; a path rewrite can also defeat a rule written for the original path |
| Load balancer | spreads load, health-checks, sometimes terminates TLS | patch the application; a single unpatched node is still reachable |
| CDN | caches and serves content close to the user, absorbs DDoS | see inside TLS to bodies (unless it terminates it), and cached content can be served to the wrong user if Cache-Control is wrong |
| WAF | blocks known-bad patterns, virtual patches for known CVEs | understand your application; encoding, chunking and case variation bypass pattern matching, and logic flaws look perfectly normal |
The pattern to internalise: edge components are for availability and for buying time, not for correctness. Every authorisation decision must be enforced in the application, because the edge will eventually be bypassed, misconfigured or reached through another path β an origin IP, an internal endpoint, or a mobile API.
Where the browser trusts
- Certificates. The padlock means the connection is encrypted and the certificate matches the name β not that the site is honest. A phishing site with a valid certificate for its own lookalike domain shows exactly the same padlock.
- Mixed content. One resource loaded over plain HTTP inside an HTTPS page lets a network attacker modify that resource β and through it, often the whole page. Modern browsers block this, but only because it is dangerous.
- Third-party scripts. Analytics, tag managers, chat widgets and A/B testing tools all execute with the full authority of your site: they can read forms, cookies and the DOM. A compromised third-party script is a compromise of your site, and it needs no vulnerability in your code at all.
The attack surface of a single web page
| Surface | Typical attack class it invites |
|---|---|
| URL parameters | injection (SQL, command, template), IDOR when an identifier is trusted, open redirects, path traversal |
| Form fields | stored and reflected XSS, injection, mass assignment when extra fields are accepted |
| Cookies | session hijacking if flags are missing, session fixation if the ID is accepted from the client |
| HTTP headers | host header injection, response splitting, cache poisoning, bypass of IP-based access rules via X-Forwarded-For |
| File uploads | web shells, malware distribution, decompression bombs, path traversal through filenames |
| Third-party JavaScript | supply-chain compromise, data skimming (Magecart-style card theft), keylogging in your own page |
| API endpoints | broken object-level authorisation, excessive data exposure, no rate limiting, verb tampering |
| Errors and metadata | stack traces, framework versions, debug endpoints, .git or backup files left in the web root |
Lesson 10 walks through each of these attack classes in detail; this table exists so that when you open a web page, you see a list of doors rather than a design.
What a defender should put in place
- TLS everywhere, with a policy that refuses obsolete protocol versions, and automatic certificate renewal so expiry stops being an outage.
- HSTS, so the browser refuses to downgrade, plus a redirect from HTTP at the very edge.
- Cookie flags β
Secure,HttpOnly,SameSiteβ on every session cookie, without exception. - A real CSP, starting in report-only mode so you can see what breaks before you enforce it.
- Authorisation at the object level. Every request re-checks that this user may touch this record. Never rely on the UI hiding a button.
- Dependency and script control. Know which third-party JavaScript is loaded, pin and review it, and remove what nobody uses.
Attack it / Defend it
| The attack | How it works | The control that stops it |
|---|---|---|
| Cross-site scripting (XSS) | attacker-controlled input is rendered as code and runs in your origin | output encoding, a restrictive CSP, HttpOnly cookies, framework auto-escaping |
| Cross-site request forgery (CSRF) | your browser is made to send a state-changing request with your cookies attached | SameSite cookies, per-request anti-CSRF tokens, re-authentication for sensitive actions |
| SQL injection | user input is concatenated into a query | parameterised queries, least-privilege database accounts, input validation |
| IDOR / broken object authorisation | changing an ID in a URL returns somebody else's record | object-level authorisation checks on every request |
| Session hijacking | the session cookie is stolen by XSS or a network attacker | Secure and HttpOnly flags, HSTS, short session lifetimes, re-issue on login |
| SSL stripping | a network attacker downgrades the connection to plain HTTP | HSTS with a long max-age, HTTPS-only at the edge, no mixed content |
| Clickjacking | your page is framed invisibly under attacker-controlled UI | X-Frame-Options: DENY or CSP frame-ancestors 'none' |
| Open redirect | a legitimate redirect parameter is pointed at an attacker's site | allowlist redirect destinations rather than validating by pattern |
| Malicious third-party script | a compromised CDN or widget runs in your origin | CSP with an explicit script allowlist, subresource integrity, fewer dependencies |
| Cache poisoning | a crafted header causes a bad response to be cached for everyone | normalise and validate headers at the edge, never cache responses to requests carrying credentials |
Key takeaways
- The request path is the attack path. Ten steps, ten places to fail, and the browser is not one of the places that enforces your authorisation.
- Statelessness is why sessions exist, and every session mechanism trades revocability for scalability. Choose deliberately.
- Cookie flags and CSP are configuration, not features. They cost nothing and they close the most common web attack classes.
- The edge protects availability, not correctness. A WAF that is not paired with object-level authorisation is a speed bump.
- Third-party JavaScript is your code as far as the browser is concerned. Every script you include is a trust decision with a real owner.
Check yourself
- List the steps between typing a URL and the page appearing, and name one attack for two of them.
- What are three flags you want on a session cookie, and what does each one stop?
- Why is a JWT payload not a safe place for secrets, and why is
alg: nonedangerous? - What does CORS actually relax, and when is that relaxation dangerous?
- A WAF is blocking SQL injection attempts at the edge. What class of attack does it not address, and why?