I have this login mechanism with an additional authentication barrier presented before the user can change sensitive information (such as their password, email, etc.) through their profile.
There is a pre-session on the login page that I use for verifying the CSRF token, and I have code responsible for regenerating the session ID before the current session is given the user data and authentication status.
For the login process, everything goes fine. The session ID before and after logging in are different. No problems here. The problem begins when I go to authentication.php, which serves as a barrier presented to the user before they can change their password. Upon successfully validating the provided password against the hash from the database, I would set a new session variable named "authenticated" that gives access to the next page, pass-change.php. Before "authenticated" is set, the session ID must be, again, regenerated.
That's where my problem lies.
Instead of taking me to pass-change.php with a brand new session ID, it destroys the session; consequently, I am taken back to login.php, presumably because $_SESSION['loggedin'] is no longer set.
// This is my session_start() function
function my_session_start() {
session_start();
if (isset($_SESSION['destroyed'])) {
// checks if session has been 'destroyed' for more than 5 minutes
if ($_SESSION['destroyed'] < time() - 300) {
// if true, wipe all session variables and throw exception
$_SESSION = array();
throw new Exception('This session is obsolete');
}
if (isset($_SESSION['new_session_id'])) {
// if new_session_id is still set, close the session and attempt to start a new session with it
session_commit();
session_id($_SESSION['new_session_id']);
session_start();
return;
}
}
}
my_session_start();
// This is my session_regenerate_id() function
function my_session_regenerate_id() {
// new session ID is created and stored for later use
$new_session_id = session_create_id();
$_SESSION['new_session_id'] = $new_session_id;
// set the current session as 'destroyed' and save current time
$_SESSION['destroyed'] = time();
// close session
session_commit();
// set the new ID we created previously and start a new session
session_id($new_session_id);
ini_set('session.use_strict_mode', '0');
session_start();
ini_set('session.use_strict_mode', '1');
// unset these variables as they should not be with the new session
unset($_SESSION['destroyed']);
unset($_SESSION['new_session_id']);
}
// Sessions are always started at the beginning of every file. my_session_regenerate_id() is called right before I define session variables containing authentication flags or user data. This is done at login.php after password is checked against the hash and deemed correct; and also called at authentication.php after the user provides their correct password.
// this is the part where I call my_session_regenerate_id() at authentication.php
if (password_verify($pass, $hash)) {
my_session_regenerate_id();
$_SESSION["authenticated"] = time();
header('Location: pass-change.php');
}
// some pages redirect when you're not logged in
if (!isset($_SESSION["loggedin"])) {
header('Location: login.php');
I expect the session to retain its status after my_session_regenerate_id() is called at authentication.php, but it gets destroyed. All it should be doing is: set current session as 'destroyed', create new session ID and change to it, while retaining all other user data and authentication flags such as $_SESSION['loggedin'].
EDIT
As requested, here are the results from printing all session variable data:
Before login, at login.php:
array(2) {
["usertoken"]=>
string(64) "519f82f974fb8e79b30ee950be9ba63048278105bd8e983fa832e754aaf47b3c"
["usrtokentime"]=>
int(1553865620)
}
After first run of session ID regeneration, at profile.php:
Session ID changed after login
array(7) {
["lastLogin"]=>
int(1553864997)
["loggedin"]=>
string(0) ""
["registerDate"]=>
int(1553605077)
["name"]=>
string(14) "User Name"
["email"]=>
string(26) "user.email@gmail.com"
["type"]=>
string(1) "A"
["usertoken"]=>
string(0) ""
}
Second run of session ID regeneration. After submitting the form at authentication.php and being thrown back to login.php:
Session ID changed again
array(3) {
["authenticated"]=>
int(1553865804)
["usertoken"]=>
string(64) "ba454364870f5d8cdfd4e5a3213d3a34117f161c098c97060e70327d3a983501"
["usrtokentime"]=>
int(1553865804)
}
So, only "authenticated" session variable survived. All others were wiped out.