Engineer's toolkit
Sessions and cookies
How a browser login stays alive. Cookie attributes that matter, session fixation, CSRF, and why server-side sessions are easier to revoke than signed tokens.
HTTP has no memory. So after a user logs in, the server hands the browser a session: a random identifier stored in a cookie. The browser sends the cookie on every request, and the server looks up what that identifier means. The cookie is the key. Whoever holds it is logged in as that user.
That makes the cookie a bearer credential: whoever holds it is logged in.
Walking through it
A login response typically sets a cookie like this:
Set-Cookie: __Host-sid=q8V2m...43chars...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=1209600Each attribute stops one attack:
| Attribute | What it blocks |
|---|---|
HttpOnly | Scripts (document.cookie) can't read the value, which limits damage from XSS |
Secure | The cookie is sent only over HTTPS, not in cleartext on the network |
SameSite=Lax or Strict | Browsers don't attach the cookie to most cross-site requests, which cuts CSRF |
__Host- prefix | Browsers accept the cookie only if it has Secure, Path=/ and no Domain, so a subdomain can't overwrite it |
Max-Age | Bounds how long a stolen cookie stays useful |
Session fixation
Suppose the attacker plants a known session ID in a victim's browser, for example through a crafted link. If the server keeps that ID when the victim logs in, the attacker now holds a logged-in session.
Fix it by issuing a new session ID at every privilege change: login, password change, MFA step-up and role change. Discard the old ID. Most frameworks have a single call for this, so check that yours rotates the ID.
CSRF
Cross-site request forgery happens when a malicious page makes the victim's browser send a request to your site. Before SameSite became the default in browsers, the browser attached your cookie automatically, so the request ran as the victim.
Two defenses work together:
SameSite=LaxorStricton the session cookie. This is the first line.- A CSRF token, a random value tied to the session and sent in a header or hidden form field. State-changing requests, such as
POST, must include it. A forged page can't read it, so it can't add it.
Don't make state changes on GET. A cross-site image tag or link can trigger a GET even with SameSite.
Server-side sessions versus signed cookies
Two designs are common:
- Server-side session. The cookie holds an opaque ID. The server stores the real state in Redis or a database. Logging out or revoking access is one delete.
- Signed or encrypted cookie. The cookie holds the state, protected by an HMAC or an AEAD. Nothing is stored on the server, but you can't revoke a single session until it expires. Rotating the signing key logs out everyone.
Prefer server-side sessions for web apps that need instant revocation. Signed tokens suit APIs spread across services, with the trade-offs covered in JWTs and token validation.
Note
A stolen session cookie needs no password, so watch for session IDs in logs, URLs and error reports.
Common mistakes
- Putting the session ID in a URL, where it lands in logs, browser history and
Refererheaders. - Keeping the same session ID after login.
- Omitting
HttpOnlyorSecurebecause local testing over HTTP was painful. - Relying on
SameSitealone for state changes that also need a CSRF token.
Check yourself
- Why does rotating the session ID at login stop fixation? Answer: the attacker's planted ID is no longer valid after the victim's privilege change.
- Why can't a server-side session be revoked when a signed cookie can? Answer: a signed cookie is valid until it expires, since the server stores nothing. A server-side session is one row to delete.
Key takeaways
- A session cookie is a bearer credential. Set
HttpOnly,SecureandSameSite, and use the__Host-prefix. - Issue a new session ID at every login and privilege change.
- Use
SameSiteplus a CSRF token, and keep state changes offGET. - Choose server-side sessions when you need instant revocation.
Further learning
OWASP's Session Management Cheat Sheet covers these attributes and the attack paths in more detail.
OWASP Session Management Cheat SheetWebsite with the collection of all the cheat sheets of the project.cheatsheetseries.owasp.orgRelated
Authentication and authorization
Authentication proves who you are, authorization decides what you can do, and service-to-service calls need their own identity. The map for the rest of this topic.
Secure randomness and tokens
Where keys, nonces, salts and session tokens must come from, why Math.random is unsafe, and how many bits a token needs.
JWTs and token validation
A JWT is a signed claim set, not a secret. How to validate one safely, the alg confusion and none attacks, and when a JWT is the wrong tool.