Skip to content

PHP Tutorial PHP Security

Session Fixation

Lesson 294 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

A session ID is like a key. In session fixation, the attacker does not steal the key. They give the victim a key that the attacker already knows, and wait for the victim to log in.

The attack

  1. The attacker visits your site and gets a session ID, say abc123.
  2. They trick a victim into using that ID, for example with a link https://shop.example/?PHPSESSID=abc123 (if the site accepts IDs in the URL), or by planting a cookie through another weakness.
  3. The victim logs in. The site marks session abc123 as logged in.
  4. The attacker, who also uses abc123, is now logged in as the victim.

The attacker never needed the password.

The fix: a new ID at login

Create a new session ID at the moment of login (and whenever privileges change). The old abc123 becomes worthless.

index.php
PHP
<?php
session_start();

if (passwordIsCorrect($email, $password)) {
    session_regenerate_id(true);       // true: delete the old session file
    $_SESSION["user_id"] = $userId;
}

The attacker’s known ID no longer leads to a logged-in session.

More protection

index.php
PHP
<?php
ini_set("session.use_strict_mode", "1");   // refuse IDs the server did not create
ini_set("session.use_only_cookies", "1");  // never accept an ID from the URL
ini_set("session.cookie_httponly", "1");
ini_set("session.cookie_samesite", "Lax");
ini_set("session.cookie_secure", "1");     // only over HTTPS
  • Strict mode stops the server from adopting an unknown ID that a client suggests.
  • Cookies only removes the ?PHPSESSID= trick.
  • HttpOnly, SameSite and Secure reduce the ways an ID can be read or planted.

Regenerate when privileges change

Call session_regenerate_id(true) also after:

  • Login.
  • Logout (you destroy the session anyway).
  • A password change.
  • Changing the user’s role or entering an “admin mode”.

Why true?

index.php
PHP
<?php
session_regenerate_id();       // the old session data stays on the server
session_regenerate_id(true);   // the old session data is deleted

Deleting the old session is safer. One caveat: on a very unreliable network, a second request that is still using the old ID may arrive just after the switch. Some frameworks keep the old session for a few seconds. For most sites, true is the right choice.

Test it yourself

  1. Open the login page and note the PHPSESSID cookie in the browser developer tools.
  2. Log in.
  3. Look at the cookie again. The value should be different. If it is the same, the site is vulnerable.

A summary table

WeaknessFix
ID unchanged after loginsession_regenerate_id(true)
Session IDs accepted in the URLsession.use_only_cookies=1
Server accepts any IDsession.use_strict_mode=1
ID readable by JavaScriptHttpOnly cookie
ID sent over HTTPSecure cookie and HTTPS

See Secure Session Practices for the complete setup.

lightbulb
A one-line habit
Wherever your code writes $_SESSION["user_id"] = ..., the line above it should be session_regenerate_id(true);.