Session Security
The session ID is a bearer token (Chapter 4) — hold it and you're the user. This chapter is about protecting that token through its whole life: stopping it being planted (fixation), stolen (hijacking), or kept alive too long (timeouts), and configuring the cookie that carries it. This is where the HttpOnly / Secure / SameSite advice from the HTTPS, CSRF, and XSS courses finally comes home — on the session cookie.
Session Hijacking: Stealing the Token
Session hijacking means obtaining a valid session ID and using it to impersonate the user. The token can be stolen several ways — each of which a previous course addressed:
| Theft route | Defence | Course |
|---|---|---|
| Sniffing plaintext HTTP | HTTPS everywhere + HSTS + Secure cookie | HTTPS |
| XSS reading the cookie | HttpOnly cookie + fix XSS | XSS |
| Riding the session cross-site | SameSite + CSRF tokens | CSRF |
| Guessing a predictable ID | high-entropy CSPRNG IDs | Auth Ch. 4 |
Session Fixation: Planting a Known Token
A more subtle attack. Instead of stealing your session ID, the attacker gives you one they already know, then waits for you to log in with it:
session.regenerate() / equivalent — and many do it automatically on login, but verify yours does. (This is also, you may recall, the most likely cause of the "Invalid CSRF token" login error from the CSRF course: the CSRF token was tied to the pre-regeneration session.)
Session Rotation More Broadly
Regenerating the ID isn't only for login. Good practice rotates the session ID at key moments to limit the value of any single captured token:
- At login — defeats fixation (above); the most important one.
- At privilege elevation — e.g. entering an admin area or re-authenticating for a sensitive action.
- Periodically — some apps rotate the ID every N requests/minutes, so a stolen ID has a short useful life (balance against UX/complexity).
- On logout — fully destroy the server-side session, don't just clear the cookie (next section).
Timeouts: Idle vs Absolute
A session shouldn't live forever — a stolen or abandoned session is a standing risk. Two complementary timeouts:
| Timeout | Expires after… | Purpose |
|---|---|---|
| Idle (inactivity) | N minutes of no activity | kills abandoned sessions (e.g. walked away from a shared PC) |
| Absolute | a fixed max lifetime since login (e.g. 8–24h) | caps how long any session — even an active stolen one — can live |
Use both: idle timeout for the common "forgot to log out" case, and an absolute cap so an attacker who steals a session can't keep renewing it indefinitely by staying active. Sensitive apps (banking) use short timeouts; consumer apps balance security against the annoyance of frequent re-login. Pair timeouts with proper logout: destroy the server-side session record and clear the cookie — clearing only the cookie leaves a valid session on the server that a stolen ID could still use.
The Cookie Flags — In Full, at Last
Everything in this course's quartet converges on these attributes of the session cookie. Set all of them:
| Flag | Effect | Stops |
|---|---|---|
| HttpOnly | cookie unreadable by JavaScript | XSS stealing the session via document.cookie |
| Secure | cookie sent only over HTTPS | sniffing the cookie on plaintext connections |
| SameSite=Lax/Strict | not sent on (most) cross-site requests | CSRF riding the session |
| __Host- prefix | forces Secure, Path=/, no Domain | cookie injection from subdomains |
Secure is the HTTPS course (don't leak it on the wire), HttpOnly is the XSS course (script can't read it), SameSite is the CSRF course (don't send it cross-site), and the cookie carries the session this course is about. Four words on one Set-Cookie header encode the lessons of all four courses. Two honest caveats carried from those courses: HttpOnly stops cookie theft but not session riding (XSS can still act in-session — fix XSS), and SameSite is strong but not complete (state-changing GETs, same-site subdomains — keep CSRF tokens). Defence in depth, as always.
Hands-On Exercises
Explain session fixation step by step and why regenerating the session ID at login defeats it. Then explain the connection to the "Invalid CSRF token" login error from the CSRF course, and list the other moments a session ID should be rotated.
📄 View solutionFor the session cookie, write the complete Set-Cookie with all security flags, and for each flag state which theft/abuse route it blocks and which prior course it comes from. Then explain why HttpOnly alone doesn't make XSS harmless, and why SameSite alone doesn't fully replace CSRF tokens.
Distinguish idle vs absolute timeout and explain why you want both. Then explain why "logout" must destroy the server-side session rather than only clearing the cookie, and what goes wrong if you only clear the cookie while a stolen ID exists.
📄 View solutionChapter 5 Quick Reference
- Session hijacking = stealing a valid ID (sniffing → Secure/HTTPS; XSS → HttpOnly; cross-site → SameSite; guessing → entropy)
- Session fixation = attacker plants a known pre-login ID; defeated by regenerating the ID at login (and privilege elevation)
- Fixation regeneration is also the likely cause of the CSRF course's "Invalid CSRF token" login error (token tied to the old session)
- Rotate the ID: at login, at privilege elevation, optionally periodically, and destroy it on logout
- Idle timeout (kills abandoned sessions) + absolute timeout (caps total lifetime) — use both
- Logout = destroy the server-side session record and clear the cookie — not just the cookie
- Cookie flags: HttpOnly (XSS), Secure (HTTPS), SameSite (CSRF), __Host- prefix — the whole quartet in one header
- Caveats: HttpOnly stops theft not riding; SameSite ≠ full CSRF defence — keep defence in depth
- Next chapter: multi-factor authentication — TOTP, passkeys/WebAuthn, and why SMS is weak