Frontend Labs
⋯

Part 10 — Web and HTTP security

The application is where most breaches actually happen. A perfect TLS configuration does nothing against SQL injection, a broken authorization check, or a poisoned dependency. This Part is the attacker's-eye view of a web app, mapped to the OWASP Top 10, with the fix for each.

Chapter 41 — How the web decides what to trust

In one sentence

Browser security rests on the origin (scheme + host + port) and the same-origin policy that isolates one site's data from another's — and almost every web vulnerability is a way to cross that boundary or abuse the server's trust in a request.

The origin

   ORIGIN = scheme  ://  host  :  port

     https://shop.securesh.op:443
     \___/     \____________/  \_/
     scheme       host        port

   Same origin ONLY if all three match exactly:
     https://shop.securesh.op        vs  http://shop.securesh.op    -> DIFFERENT (scheme)
     https://shop.securesh.op        vs  https://api.securesh.op    -> DIFFERENT (host)
     https://shop.securesh.op        vs  https://shop.securesh.op:8443 -> DIFFERENT (port)
     https://shop.securesh.op/a      vs  https://shop.securesh.op/b  -> SAME (path doesn't count)

"Site" is looser than "origin" — it's roughly the registrable domain (securesh.op), ignoring scheme, port, and subdomain. Cookies and some newer protections work at "site" granularity (eTLD+1). Know which one a given feature uses.

Same-Origin Policy (SOP)

The foundational rule: script running on origin A cannot read data from origin B.

   A page on https://evil.example CAN:
     - send requests to https://bank.example (the request goes, with cookies!)
     - load bank.example images, scripts, styles, iframes
     - navigate to it, submit forms to it

   A page on https://evil.example CANNOT:
     - READ the response body from https://bank.example (SOP blocks it)
     - read bank.example's cookies, localStorage, or DOM (in an iframe)

That gap — "the request is sent with your cookies, but the attacker can't read the reply" — is exactly why CSRF exists (the attacker doesn't need to read the reply, just to cause the side effect) and why CORS was invented (to let servers opt in to sharing responses).

Cookies — the ambient credential

Cookies are attached to every matching request automatically. That convenience is the root of a lot of pain. The attributes that matter:

   Set-Cookie: session=abc123;
       Secure;                  <- only sent over HTTPS
       HttpOnly;                <- JavaScript cannot read it (blunts XSS theft)
       SameSite=Lax;            <- not sent on most cross-site requests
                                   (Lax: sent on top-level GET navigation;
                                    Strict: never cross-site;
                                    None: always -- REQUIRES Secure)
       Path=/; Domain=securesh.op;
       Max-Age=3600;
       __Host- prefix           <- name prefix that ENFORCES Secure + Path=/
                                   + no Domain -> hardest to tamper with

Defaults to set on every session cookie: Secure; HttpOnly; SameSite=Lax (or Strict for high-value), and use the __Host- name prefix.

CORS — opting in to cross-origin reads

CORS is not a restriction you configure to be safe; it's the server telling the browser "it's OK to let this other origin read my response".

   Browser (from https://app.example) --> GET https://api.example/data
                                          Origin: https://app.example

   api.example responds:
     Access-Control-Allow-Origin: https://app.example    <- echoes ONE origin
     Access-Control-Allow-Credentials: true              <- allow cookies/auth
     Vary: Origin

   The browser then lets app.example's JS read the body. Without these
   headers, the request still HAPPENED, but JS gets an opaque error.

The classic CORS mistakes:

   Access-Control-Allow-Origin: *  WITH  Allow-Credentials: true
     -> forbidden by spec, but misconfigs/reflectors bypass it. Means
        "any site can make authenticated calls and read the response."
   Reflecting the Origin header without an allowlist -> same thing.
   Allowing  null  origin -> sandboxed iframes / redirects can hit you.
   Treating CORS as an auth mechanism -> it isn't. Non-browser clients
     ignore it entirely. CORS protects the USER's browser, not your API.

The OWASP Top 10 (2025) — the map for this Part

   A01  Broken Access Control            -> Ch 45   (still #1, by far)
   A02  Security Misconfiguration        -> Ch 41,47 (headers, defaults, CORS)
   A03  Software Supply Chain Failures   -> Ch 47
   A04  Cryptographic Failures           -> Parts 3-7 (weak/missing crypto,
                                           secrets in code, bad TLS)
   A05  Injection (incl. XSS)            -> Ch 42, 43
   A06  Insecure Design                  -> whole guide (threat model first)
   A07  Authentication Failures          -> Ch 46
   A08  Software & Data Integrity Failures -> Ch 47 (unsigned updates,
                                           insecure deserialization, CI/CD)
   A09  Logging & Alerting Failures      -> Part 11
   A10  Mishandling Exceptional Conditions -> Ch 44/45 (fail-open, verbose
                                           errors, bad error handling)
   (SSRF -> folded into A01/its own writeup) -> Ch 44

Rankings shuffle between editions; the underlying bug classes are stable. Learn the classes.

Practice (25 min)

# 1. Inspect real cookie hygiene
curl -sI https://github.com | grep -i set-cookie
curl -sI https://news.ycombinator.com | grep -i set-cookie
#   which have Secure / HttpOnly / SameSite? which don't?

# 2. Probe a CORS policy (safe, read-only)
curl -s -I -H 'Origin: https://evil.example' https://api.github.com/ | grep -i 'access-control'
curl -s -I -H 'Origin: https://evil.example' \
     -X OPTIONS https://api.github.com/ | grep -i 'access-control'
#   does it reflect your Origin? echo *? require credentials?

# 3. See SOP in your browser console (devtools on any page):
#    fetch('https://example.com').then(r=>r.text()).then(console.log)
#      -> blocked by CORS (you'll see the error; the request still went)

# 4. Security headers scan
curl -sI https://your-service.example | grep -iE \
  'content-security-policy|strict-transport|x-content-type|x-frame|referrer-policy|permissions-policy'
# or use: https://securityheaders.com  /  https://observatory.mozilla.org

Common confusions

  • "CORS makes my API secure." CORS relaxes SOP for browsers. It is not authentication or authorization, and non-browser clients ignore it. Your API still needs real authz on every endpoint.
  • "SameSite=Lax stops all CSRF." It stops most cross-site POST/AJAX CSRF, but top-level GET navigations still send the cookie, and same-site subdomains can be a gap. Keep anti-CSRF tokens for state-changing requests (Ch 44).
  • "HttpOnly means XSS can't hurt me." It stops cookie theft via JS. An XSS can still make authenticated requests as the user, read the page, keylog, etc.
  • "Origin and site are the same." Origin = scheme+host+port (exact). Site = eTLD+1 (looser). Cookies use "site"; SOP uses "origin".

Check yourself

  1. What three components make up an origin? Are http://x and https://x the same origin?
  2. Under SOP, what can evil.example do to bank.example, and what can't it?
  3. What do Secure, HttpOnly, and SameSite each protect against?
  4. Is Access-Control-Allow-Origin: * with credentials safe? What's the usual underlying mistake?
  5. Does CORS protect your API from a Python script? Why/why not?

(Answers: Appendix F.)

Further reading

  • Site: MDN Web Docs — "Same-origin policy", "CORS", "Set-Cookie", "Content Security Policy". The reference.
  • Book: The Tangled Web, Michal Zalewski — how browsers actually behave. Older but the model is unchanged and it's brilliant.
  • Site: web.dev/articles/same-site-same-origin — the origin-vs-site explainer with diagrams.
  • Course: PortSwigger Web Security Academy — "CORS" topic, with free labs.
  • Tool: securityheaders.com, Mozilla Observatory.

Generated from real-life-guide.md · 8 Oct 2026 16:36