Cybreach Consulting Prendre RDV
Back to articles
Vulnerabilities

Session management: fixation, expiration, invalidation and token in the URL

The session is the mechanism that lets an application remember that a user has authenticated. It typically takes the form of an opaque identifier stored in a cookie, sent with every request. Session management errors don't lie in the token itself but in how it's created, transmitted, kept, and destroyed. A perfectly random token can still be stolen if the session never expires.

Session fixation

Session fixation is an attack where the attacker imposes a session identifier on the victim before they authenticate. The classic scenario: the attacker obtains a valid session identifier (by visiting the site themselves), sends the victim a link containing this identifier, the victim clicks, logs in with their credentials, and the application doesn't regenerate the token. The attacker, who already knew the token, now has access to the authenticated session.

Link with fixed session (token in URL)

https://app.example.com/login?sessionid=abc123

# L'attaquant a préalablement visité le site avec ce sessionid.
# Si l'application l'accepte et ne régénère pas le token après authentification,
# l'attaquant peut utiliser ce même sessionid pour accéder à la session.

The fix is simple and non-negotiable: regenerate the session identifier immediately after every successful authentication. The token that existed before login must be invalidated and replaced with a new one. All serious session management libraries provide a method for this.

PHP example: regeneration after authentication

// Après vérification des identifiants :
session_regenerate_id(true); // true = détruit l'ancienne session
$_SESSION['user_id'] = $user->id;
$_SESSION['authenticated'] = true;

Predictable session identifier

A predictable session token can be guessed by brute force or by inference. Some applications generate their tokens from predictable information: Unix timestamp, combination of user ID and a counter, MD5 hash of the username. An attacker who understands the scheme can enumerate valid tokens.

The rule: use a cryptographically secure generator with at least 128 bits of entropy. Never build a token manually.

Secure token generation

// Node.js
const crypto = require('crypto');
const sessionToken = crypto.randomBytes(32).toString('hex'); // 256 bits

// Python
import secrets
session_token = secrets.token_hex(32)  # 256 bits

Session token in the URL

Exposing the session token in the URL is a serious mistake. URLs appear in server logs, proxy logs, browser history, the HTTP Referer header (sent to third-party sites), bookmarks, and emails. A token in the URL is a token exposed to dozens of different systems.

Token in URL (avoid at all costs)

# Mauvaise pratique
https://app.example.com/dashboard?token=abc123xyz

# Quand l'utilisateur visite un lien externe depuis cette page,
# l'en-tête Referer contient l'URL complète avec le token :
Referer: https://app.example.com/dashboard?token=abc123xyz

The session token must always travel in a cookie, never in the URL or in an Authorization header stored in localStorage (accessible to JavaScript).

Session not invalidated after logout

When a user logs out, the session must be destroyed server-side. Deleting the cookie client-side without invalidating the server session is not enough: if the attacker has intercepted the token (via XSS, log, or otherwise), they can keep using it indefinitely.

Correct logout (Node.js / express-session)

app.post('/logout', (req, res) => {
  req.session.destroy((err) => {  // Détruit la session côté serveur
    res.clearCookie('connect.sid'); // Supprime le cookie côté client
    res.redirect('/login');
  });
});

Excessive lifetime

A session that never expires, or that expires after 30 days, is a permanent exploitation window. If the token is compromised (log, XSS, shoulder surfing), the attacker has unlimited time-based access. The lifetime should be proportional to the application's sensitivity.

Best practice: absolute duration (e.g., 8 hours) combined with an inactivity timeout (e.g., 30 minutes). Both independently: a token can remain valid for 8 hours even if the user does nothing, or expire after 30 minutes of inactivity, whichever comes first.

Summary

  1. Regenerate the token after authentication: neutralises session fixation
  2. Use a cryptographic generator: at least 128 bits of entropy, never manually built
  3. Transport the token in a cookie only: never in the URL, never in localStorage
  4. Invalidate the session server-side on logout: deleting the cookie is not enough
  5. Measured lifetime: absolute duration + inactivity timeout, calibrated to the application's sensitivity

A question after reading?

Doubts about your session management? Send a message.

Or book a 30-minute scoping call directly

Book a call