Lukas' Notes

HttpOnly and Secure are the cookie flags people reach for first, and they read like a complete story: HttpOnly stops JavaScript from reading the cookie, Secure stops it from leaving over HTTP. Between them, the cookie is confidential — nobody steals it. Notice what the two flags never promise: that the cookie you actually send is the one the server issued.

That gap is where the session actually lives. A session id is a name; the server accepts whichever id the client presents and looks up the state behind it. So the question “which session are you in?” is answered by the contents of the request’s Cookie header, not by anything the application checks. An attack that can plant a different session id into that header — without ever stealing the original — affects the victim just as thoroughly as a hijack would.

Cookie tossing makes this concrete. A same-site attacker under evil.bank.com sets Set-Cookie: SESSID=s_atk; domain=bank.com; path=/account/. The cookie jar rule for plus browsers’ most-specific-path-first ordering means that on a request to /account/, the attacker’s cookie appears before the genuine one in the Cookie header, and most servers take the first match. The victim’s own session cookie is still there — untouched, untouched-able by the attacker — and yet the server now treats the victim as the attacker. Confidentiality was preserved; integrity was not.

Session fixation exploits the same gap from the other side. The attacker does not even need their own session — they take a pre-auth session id they obtained from bank.com, plant it as a domain=bank.com cookie on the victim, and then wait. The victim logs in, the browser’s pre-planted id is sent with the login request, the same id is “promoted” to authenticated state, and the attacker — who knew it all along — joins the victim’s session. The genuine cookie was never read; the genuine session was never stolen; the session id was simply chosen by the wrong party.

Cookie jar overflow is the integrity attack that does not even need a new cookie value — it just removes the victim’s. Each per-site jar is bounded (~180 cookies); an attacker who keeps setting cookies can age the victim’s session cookie out of the jar, and HttpOnly does nothing because it never promised durability, only inaccessibility to script. Evicting a __Host- cookie can also re-open the door to tossing.

What actually defends cookie integrity, then, is a different family of mechanisms: __Host- and __Secure- prefixes that lock cookies to a host; rotating the session id on every privilege change (the standard fix for fixation); and treating cookies as a state channel the browser controls rather than as an opaque token the server just echoes back. Synchroniser-token CSRF defences beat double-submit specifically because they store the token inside the signed session — overwriting the cookie now overwrites the comparison token too, so the attack fails instead of succeeds.

The corrected mental model: a session cookie is not a secret you hide from the attacker — it is the answer the browser gives to the server’s question “who are you?” The standard flags protect that answer from being read, but they do not protect it from being swapped, evicted, or pre-planted. Integrity of the session id is a separate property from confidentiality of the cookie value, and it requires its own defences.