You visit a website, enter your username and password, and click Login. The server verifies your credentials. Successful.
Now comes the interesting part.
HTTP is stateless. The protocol itself doesn't remember anything between requests. Every request the browser sends is, from HTTP's perspective, a fresh interaction. But you just logged in, and the server needs to recognize you across dozens of subsequent requests without you entering your password again.
So how does it do that?
Sessions: The Layer That Remembers You
After verifying your credentials, the server creates a session: a record of your authenticated state. It generates a session identifier, a value that maps to that authenticated record, and sends it to the browser, typically through a cookie. The browser stores it and automatically includes it in every subsequent request to that domain.
Browser
↓
Username + Password
↓
Server
↓
Authentication succeeds
↓
Session created
↓
Session ID sent to browser as cookie
↓
Future requests include session ID automatically
↓
Server maps session ID → authenticated session → user account
A session and a cookie are not the same thing. The session is the server-side state. The cookie is often just the mechanism the browser uses to carry the session identifier back and forth. The identifier itself is typically an opaque, random-looking value that means nothing on its own. Its meaning comes from the server looking it up.
Once this flow is established, the password is no longer involved. The session identifier has taken over.
The Session Identifier Is Now a Credential
This is the insight at the center of session hijacking.
After successful authentication, whoever presents a valid session identifier to the server may get treated as the authenticated user. The server receives a request, finds a session ID in the cookie header, looks it up, confirms it's valid, and proceeds.
GET /account
Cookie: session_id=a7f3b9...
The server does something conceptually like this:
session_id
↓
look up session
↓
authenticated user
↓
process request as that user
Now suppose an attacker obtains that session ID. They don't need your password. They just need the identifier:
Attacker
↓
stolen session_id
↓
Server
↓
valid authenticated session
↓
request processed as the authenticated user
That's session hijacking: obtaining or abusing an authenticated session credential to interact with an application as another user.
How Session Credentials Can Be Exposed
There's no single method. The session identifier can be exposed through several different paths.
Unencrypted transmission. If session cookies travel over HTTP rather than HTTPS, someone positioned to observe that network traffic may be able to capture them. The session identifier is a credential, and unprotected transmission treats it carelessly.
Cross-Site Scripting. If the application has an XSS vulnerability, malicious JavaScript can execute in the victim's browser within the application's origin. A common assumption is that HttpOnly cookies prevent XSS from stealing session tokens directly, which is true: a cookie marked HttpOnly can't normally be read by JavaScript. But this doesn't make XSS harmless for sessions. Attacker-controlled JavaScript can still make authenticated requests from the victim's browser using their existing session, without needing to extract the cookie value at all.
Compromised endpoints. If an attacker controls the user's device, session credentials stored by the browser may be accessible directly.
Application mistakes. Session identifiers sometimes end up in places they shouldn't: URL parameters, server logs, browser history, Referer headers. Each leakage point is another way the credential can reach unintended parties.
The Cookie Security Attributes
Three cookie attributes are relevant here, and each addresses a different part of the threat model.
Secure tells the browser to send the cookie only over HTTPS. This protects the session identifier during transmission but says nothing about what happens to it afterward.
HttpOnly prevents normal JavaScript from directly reading the cookie value. This limits XSS payloads from extracting the raw token. It doesn't prevent XSS from making authenticated requests on the victim's behalf.
SameSite controls whether the browser sends the cookie with cross-site requests. Strict mode prevents sending in cross-site contexts entirely. Lax mode allows the cookie with top-level navigations but not with cross-site subresource requests. This can help reduce exposure to certain cross-site request attacks, but it's not a general session-hijacking defense.
Used together, these attributes narrow the attack surface. None of them individually solves the problem.
Session Fixation: A Related but Different Attack
Session hijacking and session fixation are often confused.
Session hijacking: the attacker obtains an existing authenticated session identifier and uses it.
Session fixation: the attacker causes the victim to authenticate using a session identifier that the attacker already knows or controls. If the application doesn't replace the session identifier after login, the attacker's pre-known identifier becomes an authenticated session without the attacker having stolen anything.
The standard defense against fixation is session rotation: after successful authentication, issue a new session identifier and discard the old one. This ensures that any identifier an attacker might have planted before login doesn't survive into the authenticated state.
The Session Lifecycle Matters
Protecting a session isn't only about protecting the cookie at the moment of transmission. The full lifecycle is relevant.
After login, the session identifier should be fresh and unpredictable. It should travel only over HTTPS. The browser cookies carrying it should have appropriate attributes. If the user's authentication level changes, such as after re-entering a password for a sensitive operation, issuing a new identifier is appropriate.
When the user logs out, the server should invalidate the session. Deleting the cookie from the browser isn't sufficient on its own when sessions are managed server-side; if the server still considers the session valid, a copy of the identifier can still be used.
Session expiration limits how long a stolen credential remains useful. An idle timeout reduces the window further. Neither prevents theft, but they shorten the period during which a stolen identifier has value.
Bearer Tokens Have the Same Problem
Not every application uses traditional server-side sessions. Some issue signed tokens like JWTs that the browser stores and sends with requests. The server validates the token's signature rather than looking it up.
A JWT is still a bearer credential. If an attacker obtains a valid token, they can replay it until it expires or is otherwise invalidated. JWTs don't solve session hijacking; they change the mechanism while keeping the fundamental property: whoever has the valid credential can use it.
Session Hijacking vs CSRF
Since CSRF appeared in an earlier article, the distinction is worth stating clearly.
CSRF tricks the victim's authenticated browser into sending an unwanted request, using the browser as an intermediary without the attacker needing the session credential itself.
Session hijacking involves the attacker obtaining or abusing the credential directly, so they can make requests independently of the victim's browser.
The attacks exploit different properties of the authentication model.
Your password proves who you are at login. After that, the session credential takes over. Every subsequent request is authenticated by that identifier, not by the password.
If the session credential is exposed, authentication has been bypassed without the attacker ever touching the password. The attack works because the credential, once issued, is valuable in itself.
That's why protecting authentication doesn't end when the password is verified. The session that follows has its own lifecycle, and every stage of it, creation, transmission, rotation, expiration, and invalidation, is part of the security model.
The question "how can someone steal your login without knowing your password?" has a specific answer: because after login, the password isn't what proves who you are anymore.
Top comments (0)