A stolen session cookie lets an attacker walk in as you without ever knowing your password.
Phishing tricks you into handing over a credential or a live session — a lookalike page, a panic email, a fake "verify your account" link. The prize isn't always your password. If the page can read your session cookie, the attacker is already logged in.
A session cookie is a bearer token: whoever carries it is treated as you. That's why multi-factor authentication at login doesn't save you here — the session was already minted, and MFA is never re-checked on each request. Defence shifts from "prove who you are once" to "watch the live session and be able to kill it."
The server keeps sessions in a store it controls, hands out an opaque id in a locked-down cookie, and treats every request as untrusted until it re-reads that session and checks it still looks like the same client.
// 1. On login: mint a server-side session, hand back a hardened cookie.
res.cookie('sid', newSessionId(), {
httpOnly: true, // JS (and any XSS) cannot read the cookie
secure: true, // only sent over HTTPS
sameSite: 'Lax', // not sent on cross-site POSTs
maxAge: 15 * 60_000 // short TTL — re-issued as the user stays active
});
sessions.set(sid, { user: 'alice', ip, ua, role: 'user' });
// 2. On every request: look the session up server-side and re-check it.
function authenticate(req) {
const s = sessions.get(req.cookies.sid);
if (!s) return reject('no live session'); // revoked or expired
if (impossibleTravel(s.ip, req.ip)) { // anomaly fires
sessions.delete(req.cookies.sid); // revoke now
return reject('session anomaly — re-auth required');
}
return s;
}
// 3. On login or privilege change: rotate the id so an old one is dead.
function rotate(oldSid) {
const s = sessions.get(oldSid);
sessions.delete(oldSid);
const fresh = newSessionId();
sessions.set(fresh, s);
return fresh; // sid=a1f9... -> sid=b7c2...
}
| Signal | What it suggests | Action |
|---|---|---|
| Impossible-travel IP | Same session is live in two places too far apart to be one person | Revoke the session, force re-auth |
| New device fingerprint mid-session | The cookie moved to a machine it wasn't issued to | Step-up auth or revoke |
| Concurrent sessions from distant geos | The same token is being replayed in parallel | Kill all but the trusted session |
| Sudden privilege use | A hijacked session reaching for admin or money actions | Re-auth before the action, alert |
| User-agent flip | Browser or OS string changed under a stable session | Rebind or revoke, raise the risk score |
HttpOnly: any cross-site scripting (XSS) bug can read the cookie from JavaScript and exfiltrate the session in one line.SameSite=None with no other binding: the cookie rides along on cross-site requests with nothing else (device, IP velocity, origin checks) standing between an attacker and replay.Alice logs in from her laptop in NYC; the server mints sid=a1f9 in an HttpOnly; Secure cookie and stores { user: alice, ip: 203.0.113.10 }. She clicks a lookalike "billing alert" link; the page quietly captures and ships the cookie value. Four minutes later sid=a1f9 replays from a datacenter IP in another country. The session is technically valid, but the impossible-travel rule fires: four minutes is not enough time to cross continents. The server revokes a1f9, forces Alice to re-authenticate, and rotates her to a fresh sid=b7c2 bound to her real device. The attacker's next replayed request hits a dead session and gets a 401.
True or false: requiring MFA at login fully protects you against a stolen session cookie.