Prevent Session Fixation with session_regenerate_id in PHP
This article explains the security vulnerability known as session
fixation, details how malicious actors exploit it to hijack user
sessions, and provides a straightforward guide on how to secure your PHP
applications against this threat using the built-in
session_regenerate_id() function.
What is Session Fixation?
Session fixation is a web security vulnerability where an attacker steals a user’s session by establishing a known session ID before the user even logs in. Instead of stealing a session ID after login, the attacker “fixes” the session ID beforehand and forces the victim’s browser to use it.
The typical attack workflow happens in three steps: 1. The
Attacker Obtains a Session ID: The attacker visits the target
website, receives a valid session ID (e.g.,
PHPSESSID=12345), and keeps it active. 2. The
Attacker Tricks the Victim: The attacker sends a link to the
victim containing the fixed session ID (for example,
http://example.com/?PHPSESSID=12345) or injects the session
cookie into the victim’s browser. 3. The Victim Logs
In: The victim clicks the link and logs into their account.
Because the application does not change the session ID upon
authentication, the victim’s authenticated state is now tied to the ID
12345. 4. The Attacker Gains Access: The
attacker, who already knows the session ID is 12345,
accesses the site using that ID and gains full access to the victim’s
authenticated account.
Preventing Session Fixation in PHP
The most effective way to prevent session fixation is to change the session ID immediately after a user’s privilege level changes, such as during a successful login.
PHP provides a built-in function specifically for this purpose:
session_regenerate_id(). This function replaces the current
session ID with a new, randomly generated one while keeping the existing
session data intact.
How to Use session_regenerate_id()
To secure your authentication flow, you must call
session_regenerate_id(true) immediately after verifying the
user’s credentials and before setting any session variables that
indicate they are logged in.
Here is a practical example of how to implement this in a PHP login script:
<?php
session_start();
// 1. Retrieve and validate user credentials
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if (validate_credentials($username, $password)) {
// 2. Prevent Session Fixation by regenerating the ID
// Passing 'true' deletes the old session file on the server
session_regenerate_id(true);
// 3. Mark the user as authenticated
$_SESSION['authenticated'] = true;
$_SESSION['username'] = $username;
// Redirect to the dashboard
header("Location: dashboard.php");
exit;
} else {
// Handle login failure
echo "Invalid username or password.";
}
?>Why Pass “true” to session_regenerate_id()?
The session_regenerate_id() function accepts a boolean
parameter called $delete_old_session.
session_regenerate_id(false)(Default): Generates a new ID but keeps the old session file on the server.session_regenerate_id(true): Generates a new ID and immediately deletes the old session file containing the user’s data from the server.
You should always pass true during a login event.
Deleting the old session file ensures that the attacker’s fixed session
ID becomes instantly invalid and completely useless.