Session Security

Chapter 5
Session Security
Fixation, hijacking, rotation, timeouts — and the cookie flags in full

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 routeDefenceCourse
Sniffing plaintext HTTPHTTPS everywhere + HSTS + Secure cookieHTTPS
XSS reading the cookieHttpOnly cookie + fix XSSXSS
Riding the session cross-siteSameSite + CSRF tokensCSRF
Guessing a predictable IDhigh-entropy CSPRNG IDsAuth 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 fixation, step by step: 1. Attacker obtains a valid pre-login session ID (e.g. visits the site). 2. Attacker tricks the victim into using THAT id (a crafted link, or by setting the cookie via another vuln). 3. Victim logs in — and the server keeps the same session id. 4. The id is now an AUTHENTICATED session — and the attacker knows it. The attacker uses it and is logged in as the victim.
The fix is one rule: regenerate the session ID on every privilege change
Session fixation works only if the session ID stays the same across the login boundary. The defence is simple and non-negotiable: generate a brand-new session ID at login (and at any privilege elevation — e.g. stepping up to admin). The pre-login ID the attacker planted becomes worthless because the authenticated session has a fresh, unknown ID. Frameworks expose this as 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:

TimeoutExpires after…Purpose
Idle (inactivity)N minutes of no activitykills abandoned sessions (e.g. walked away from a shared PC)
Absolutea 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:

Set-Cookie: sessionId=9f8c…; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600
FlagEffectStops
HttpOnlycookie unreadable by JavaScriptXSS stealing the session via document.cookie
Securecookie sent only over HTTPSsniffing the cookie on plaintext connections
SameSite=Lax/Strictnot sent on (most) cross-site requestsCSRF riding the session
__Host- prefixforces Secure, Path=/, no Domaincookie injection from subdomains
The whole quartet in four attributes
Look at what these flags map to: 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

Exercise 1

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 solution
Exercise 2

For 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.

📄 View solution
Exercise 3

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 solution

Chapter 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