Here is an example of PHP code that is vulnerable to sessions that never expire and a logout that does not invalidate them:
🥺 Vulnerable Code
<?php
session_start();
if (password_verify($_POST['password'], $user['hash'])) {
// Vulnerable: the pre-login session id is reused and never expires
$_SESSION['user_id'] = $user['id'];
setcookie('remember', $user['id'], time() + 60 * 60 * 24 * 365);
}
function logout() {
// Only the client-side value is dropped - the server session stays valid
unset($_SESSION['user_id']);
}Three problems stack up here. The session id from before authentication is kept, which is the session fixation pattern. There is no idle or absolute timeout, so a cookie copied off a shared laptop still works months later. And logout only clears one key in the array: the session file lives on, and the remember cookie is a plain user id that anyone can edit to impersonate another account.
😎 Secure Code
Here is a version of the same code that is secured against sessions that never expire and a logout that does not invalidate them:
<?php
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
if (password_verify($_POST['password'], $user['hash'])) {
session_regenerate_id(true); // new id on privilege change
$_SESSION['user_id'] = $user['id'];
$_SESSION['created_at'] = time();
$_SESSION['last_seen'] = time();
}
function enforce_session_limits(): void {
$absolute = 8 * 3600; // hard cap on session lifetime
$idle = 30 * 60; // inactivity cap
if (time() - $_SESSION['created_at'] > $absolute
|| time() - $_SESSION['last_seen'] > $idle) {
logout();
header('Location: /login?expired=1');
exit;
}
$_SESSION['last_seen'] = time();
}
function logout(): void {
$_SESSION = [];
session_destroy(); // server-side record removed
setcookie(session_name(), '', time() - 3600, '/', '', true, true);
}Regenerating the id at login kills fixation, the idle and absolute limits bound how long a stolen cookie is useful, and session_destroy() plus an expired cookie means logout actually ends the session on both sides. If you offer remember-me, store a random high-entropy selector and a hashed verifier server-side, rotate it on every use, and give users a way to see and revoke their active sessions.