Jump to content

Php cookies and session data expiring at different times


Recommended Posts

So. I'm part way through implementing a "remember me" function on my site, however before i had coded my site with mostly session variables (for "username", "user_id", etc). Though this seemed to work i realised that although the cookies would take a month to expire (because they do), the Sessions would expire very shortly, leaving me with with empty variables for important stuff like the "username" and "user_id". Do you see anything wrong with me putting... 

$_SESSION["username"] = $_COOKIE["remember"];

.. a few times to keep it live/living.

Not sure.

Perhaps i could place an if (isset) on the Session variable and if not set use the cookie, which means i would need to put a user_id and username into two additional cookies. Is that secure?

Tnx.

 

 

--- Edit ---

Would  placing this code in my file work?

    ini_set("session.use_strict_mode", 1);
    ini_set("session.cookie_httponly", 1);
    ini_set("session.cookie_secure", 1);
    ini_set("session.use_only_cookies", 1);

    ini_set("session.gc_maxlifetime",60 * 60 * 24 * 14); // 2 weeks
    session_set_cookie_params(60 * 60 * 24 * 14,"/",".yourdomain.com"); // 2 weeks

    session_name("AUTHID");
    if(isset($_COOKIE['AUTHID'])){
       session_id($_COOKIE['AUTHID']);
    }

session_start();

@ got from https://stackoverflow.com/a/54331212 O0

Edited by oz11
more info on code i found

do not store any user information in cookies. anyone can set cookies to any value and can impersonate a user.

to do what you are asking, generate a unique token, store the token in a cookie and store it in a row in a 'remember me' database table, along with the user's id and things like when the remember me was set and when you want it to expire if not regenerated.

if you receive a cookie containing a token, query to get the user's id and the expire datetime to determine if the token is valid. if it is, set the normal session user_id variable to indicate who the logged in user is.

you should only store the user id in a session variable, then query on each page request to get any other user information, such as the username, permissions,... this will insure that an change/edit in this user information will take effect on the very next page request.

Edited by mac_gyver
  • Great Answer 2

Hey Mac. 

  1. Quote

     

    1. Generated a random token which is independent of username or password.
    2. This token can then be set in a cookie on the client side.
    3. A hash of the token is stored in the database, together with the userid (in this case, users table // as "cookie_token")
    4. If the user visits the site the next time, instead of asking for the password, one can read the token from the cookie, hash it again and compare it with the already stored token.
    5. If the hashes match, the user is allowed to access the site without entering the username and password

     

     

Taking in consideration your suggestions and above. I managed to follow, but also use md5 hash on a set of random of characters..

    $length = random_bytes('25');
    $token = bin2hex($length);

.. store this "$token" as "cookie_token" in the users db md5 hashed.. and then compare the md5 hash of the cookie to the token in the db...

    echo $info['cookie_token']; // <--
    echo "<br>";
    echo md5($_COOKIE["token"]); // <<<< -- match?";

see:

    if($str1 != $str2){
        return false;
        //header("location: login.php");
    }elseif($str1 == $str2)
    {
        return true;
    } 

As for expiry dates... Instead of using a expiry date in the table i have opted for a simple. .

setcookie("token", $token, time() + (86400 * 30), "/");

.. sort of thing. This is fine as  users will have the same "remember me" period.

 

Le problem is i just don't know how to manage the expiring sessions.
 

Edited by oz11

I think you have to realize that sessions always expire when the client shuts down the browser.  Cookies and dbs last as long as you want them to.  Use the latter to feed the session when the authentication process occurs and you'll be fine until you end your activity once again.

Starting with a basic fact:  Cookies are owned by the user.  Heed Mac's advice on this.

  • A remember me cookie is a standin for a user having presented their name/password for authentication.  
  • You have implemented Mac's idea for the most part, which is standard

The only time you need evaluate the remember me cookie is if you have an unauthenticated user.   Rather than prompting for a login, you can use the remember me cookie to validate they are who they say they are, via the remember me cookie.  So that cookie requires both username and the hash value.

You need the expire date for this, because again, you can not trust the cookie.  A user could just go in and set the expiration date so the cookie never expires.   You can also use the cookie expiration as an added check if you want.  This would further verify the user has not tampered or constructed a remember me cookie to bypass login.

For all these reasons, sessions do not matter.  

  • If user is unauthenticated
  • Do they have a remember me cookie?
  • Check the database for the remember me value and check that the value has not expired
    • If this criteria is matched, log the user in
      • This should involve the exact same loading of session data as if the user had logged in with username/password.
    • Otherwise redirect to login page

One other thing I would say about remember me, is that a good additional security feature is to set a session variable boolean like "usedRememberMe".   Any time a user escalates privilege (ie. they want to change something in their profile like an email address, or create an order, or become a system moderator or superuser) you want to prompt for re-authentication and generate a new session id.    You can use the "usedRememberMe" session variable as a factor in what you might do in this circumstance.  For example, you might choose to require re-authentication more aggressively if they logged in via the remember me cookie.  It can be helpful to keep track in the session how the user was authenticated.

 



Thanks everyone! Gizmola I added the expiry date to the "users" table along with md5 token as you suggested. Works great (i think) :birthday:

 

  • I have a question though about something else related to this... the bellow code relies on a cookie named "remember" to check whether the login is via sessions (non-remembered) or cookie (remembered). Just not sure if it is secure or not..? 
  • I have a sneaking suspicion that it is a vulnerability, though not sure how else to do what i need to do, securely.
  • It's used as its a method of not evaluating session data if the remember me option has been used. 

 

dashboard (dashboard.php) and user only pages // first segment:

<?php session_start();

$page_title = $_SESSION['username']."'s User Dashboard";
include 'header.php';
include 'includes/functions/remember_token.php';

if (isRemembered($pdo) == 0)
{
    if (!isset($_SESSION['loggedin']) OR $_SESSION['loggedin'] != true) {
    
        header("location: login.php");
        exit;
    } 
    echo "good. not remembered but still passes as logged in via sessions";
}
elseif (isRemembered($pdo) == 1) {
    if (tokenLoggedIn($pdo) == false){
        header("location: login.php");
        echo "bad. remembered but not allowed";
        exit;
    } elseif(tokenLoggedIn($pdo) == true) {
        echo "good. remembered and (passes denied/allowed) so logged in";
    }
}

// checks good. progress to page content..

 

 

Functions (remember_token.php):

<?php
include '../config.php';
session_start();

function setRememberMeToken($pdo, $user_id) {

    // -------------------------------------
    //random_bytes () function in PHP
    $length = random_bytes('25');
    //Print the result and convert by binaryhexa
    $token = bin2hex($length);
    // -------------------------------------
    setcookie("token", $token, time() + (86400 * 30), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["token"] = $token;
    setcookie("remember", "true", time() + (86400 * 30), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["remember"] = "true";   // set for no-remember

    // INsert into DB ("token")
    $sql = "UPDATE users SET cookie_token=? WHERE user_id=?";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([md5($token), $user_id]);

    // --------

    $stmt = $pdo->prepare("SELECT cookie_token, name FROM users WHERE user_id=?");
    $stmt->execute([$user_id]); 
    $info = $stmt->fetch();

    echo $info['cookie_token'] ."<<<< -- match";
    echo "<br>";
    echo md5($_COOKIE["token"]) ."<<<< -- match";

    setcookie("token_user", $user_id, time() + (86400 * 30), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["token_user"] = $user_id;

    $start_date = date("Y/m/d");  
    $date = strtotime($start_date);
    $date = strtotime("+7 day", $date);
    $to =  date('Y-m-d', $date);

    $sql = "UPDATE users SET cookie_expire=? WHERE user_id=?";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$to, $user_id]);


}


function tokenLoggedIn($pdo) {

    //$user_id= $_COOKIE["token_userid"];
    $_COOKIE["token"];

    $stmt = $pdo->prepare("SELECT user_id, name, FROM users WHERE cookie_token=?");
    $stmt->execute([md5($_COOKIE['token'])]); 
    $info0 = $stmt->fetch();

    
    
    $stmt = $pdo->prepare("SELECT cookie_token FROM users WHERE user_id=?");
    $stmt->execute([$info0['user_id']]); 
    $info = $stmt->fetch();
    
//------------
    $stmt = $pdo->prepare("SELECT cookie_expire FROM users WHERE cookie_token=?");
    $stmt->execute([$info['cookie_token']]); 
    $info1 = $stmt->fetch();
    //echo "<br>";
    $expireDate = $info1['cookie_expire'];
    //echo "<br>";
    $today = date("Y-m-d");  
    //echo "<br>";
    
    $startdate = new DateTime($today);
    $now = new DateTime();
    $enddate = new DateTime($info1['cookie_expire']);

    if($startdate <= $now && $now <= $enddate) { // between 
        echo "Yes";
            $str1 =  $info['cookie_token'];
            $str2 = md5($_COOKIE["token"]);
            if($str1 != $str2){
                return false;
                //header("location: login.php");
            }elseif($str1 == $str2)
            {
                return true;
                $_SESSION["username"] = $info0['name'];
                $_SESSION['the_usr_id'] = $info0['user_id'];
                // GOOD!
            } 
    }else{
        echo "No";
    }
// ---------------




}
function isRemembered($pdo) {
    if(isset($_COOKIE["remember"])){
        return true;
    } elseif(!isset($_COOKIE["remember"])){
        return false;
    }
}

?>

(I know it has unnecessary separate SQL queries, but i'm going to clean that up later) :)

Edited by oz11

*

slight  update to remember_token.php

...

(updated bit)

function tokenLoggedIn($pdo) {

    //$user_id= $_COOKIE["token_userid"];
    $_COOKIE["token"];

    $stmt = $pdo->prepare("SELECT user_id, name, cookie_token, cookie_expire FROM users WHERE cookie_token=?");
    $stmt->execute([md5($_COOKIE['token'])]); 
    $info0 = $stmt->fetch();

    //echo "<br>";
    $expireDate = $info0['cookie_expire'];
    //echo "<br>";
    $today = date("Y-m-d");  
    //echo "<br>";
    
    $startdate = new DateTime($today);
    $now = new DateTime();
    $enddate = new DateTime($info0['cookie_expire']);

    if($startdate <= $now && $now <= $enddate) { // between 

            $str1 =  $info0['cookie_token'];
            $str2 = md5($_COOKIE["token"]);
            if($str1 != $str2){
                return false;
                //header("location: login.php");
            }elseif($str1 == $str2)
            {
                return true;
                $_SESSION["username"] = $info0['name'];
                $_SESSION['the_usr_id'] = $info0['user_id'];
                // GOOD!
            } 
    }else{
        echo "No";
    }
// ---------------

 

All of remember_token.php (whole file/ UPDATED):

<?php
include '../config.php';
session_start();


function setRememberMeToken($pdo, $user_id) {

    // -------------------------------------
    //random_bytes () function in PHP
    $length = random_bytes('25');
    //Print the result and convert by binaryhexa
    $token = bin2hex($length);
    // -------------------------------------
    setcookie("token", $token, time() + (86400 * 30), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["token"] = $token;
    setcookie("remember", "true", time() + (86400 * 30), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["remember"] = "true";   // set for no-remember

    // INsert into DB ("token")
    $sql = "UPDATE users SET cookie_token=? WHERE user_id=?";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([md5($token), $user_id]);

    // --------

    $stmt = $pdo->prepare("SELECT cookie_token, name FROM users WHERE user_id=?");
    $stmt->execute([$user_id]); 
    $info = $stmt->fetch();

    echo $info['cookie_token'] ."<<<< -- match";
    echo "<br>";
    echo md5($_COOKIE["token"]) ."<<<< -- match";

    setcookie("token_user", $user_id, time() + (86400 * 30), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["token_user"] = $user_id;

    $start_date = date("Y/m/d");  
    $date = strtotime($start_date);
    $date = strtotime("+7 day", $date);
    $to =  date('Y-m-d', $date);

    $sql = "UPDATE users SET cookie_expire=? WHERE user_id=?";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$to, $user_id]);


}


function tokenLoggedIn($pdo) {

    //$user_id= $_COOKIE["token_userid"];
    $_COOKIE["token"];

    $stmt = $pdo->prepare("SELECT user_id, name, cookie_token, cookie_expire FROM users WHERE cookie_token=?");
    $stmt->execute([md5($_COOKIE['token'])]); 
    $info0 = $stmt->fetch();

    //echo "<br>";
    $expireDate = $info0['cookie_expire'];
    //echo "<br>";
    $today = date("Y-m-d");  
    //echo "<br>";
    
    $startdate = new DateTime($today);
    $now = new DateTime();
    $enddate = new DateTime($info0['cookie_expire']);

    if($startdate <= $now && $now <= $enddate) { // between 

            $str1 =  $info0['cookie_token'];
            $str2 = md5($_COOKIE["token"]);
            if($str1 != $str2){
                return false;
                //header("location: login.php");
            }elseif($str1 == $str2)
            {
                return true;
                $_SESSION["username"] = $info0['name'];
                $_SESSION['the_usr_id'] = $info0['user_id'];
                // GOOD!
            } 
    }else{
        echo "No";
    }
// ---------------




}
function isRemembered($pdo) {
    if(isset($_COOKIE["remember"])){
        return true;
    } elseif(!isset($_COOKIE["remember"])){
        return false;
    }
}

?>

 

code before was broken, and i cleaned up some SQL queries. Sorry about the spamming.

 

Part of login.php

                        if (isset($_POST['remember-me'])){
                            $_SESSION["loggedin"] = true;
                            $_SESSION["username"] = $username;
                            $_SESSION['the_usr_id'] = $user['user_id'];

                            echo "<hr>";
                            echo setRememberMeToken($pdo, $user['user_id']);
                            echo "<hr>";
                            header("location: dashboard.php");
                            
                        }  
                        if (!isset($_POST['remember-me'])) {
                            $_SESSION["loggedin"] = true;
                            $_SESSION["username"] = $username;
                            $_SESSION['the_usr_id'] = $user['user_id'];

                            echo "<hr>";
                            echo "<hr>";
                            header("location: dashboard.php");

                        }

How does it look?

Edited by oz11

So it looks like you are using your own tokens for login.  That is not a good idea.  You should be relying on the session instead.  If you expect to have a cluster of app servers, you might need to change session storage so that it uses your database, or redis/memcached instead of files, or you can use a load balancer that supports the configuration of a "sticky" session, but otherwise, you don't want to be creating and managing your own session/authentication token for anything other than the remember me feature.  Sessions already, when properly configured, utilize a cookie.  You also want to make liberal use of session_regenerate_id.

From what you posted, this has DRY/ logic issues:

                        if (isset($_POST['remember-me'])){
                            $_SESSION["loggedin"] = true;
                            $_SESSION["username"] = $username;
                            $_SESSION['the_usr_id'] = $user['user_id'];

                            echo "<hr>";
                            echo setRememberMeToken($pdo, $user['user_id']);
                            echo "<hr>";
                            header("location: dashboard.php");
                            
                        }  
                        if (!isset($_POST['remember-me'])) {
                            $_SESSION["loggedin"] = true;
                            $_SESSION["username"] = $username;
                            $_SESSION['the_usr_id'] = $user['user_id'];

                            echo "<hr>";
                            echo "<hr>";
                            header("location: dashboard.php");
                        }

 

Again, I don't have your code, but you have a repetition of code, and worse yet that code is actually not relevant to the variable you are checking (!isset($_POST['remember-me']).  What you want to do is avoid blocks like this, which are also mutually exclusive.  So again, assuming that this is part of a block where you already established successfull login previously, you can rewrite your code like this, to separate the remember-me check so that it only does what is relevant to the existence of that flag.  

I will also point out that if the user logs in without the remember me checkbox, you should remove the remember me token, but your code doesn't do that.  

Something like this would be better, and also fix your current hole.

    // Assumes authentication succeeded above this code

    $_SESSION["loggedin"] = true;
    $_SESSION["username"] = $username;
    $_SESSION['the_usr_id'] = $user['user_id'];  // Not sure why you need this?

    if (isset($_POST['remember-me'])) {
    	setRememberMeToken($pdo, $user['user_id']);    
    } else if (!$_SESSION['rememberMeLogin']) {
        // Was not a "remember me" authentication AND remember me was unchecked.  So should remove the remember me token & Delete the cookie.
        unsetRememberMeToken($pdo, $user['user_id']);
    }

    header("location: dashboard.php");
    exit;
                        

 

Another thing I would suggest is not to use md5, but used sha1 instead.  md5 has a smaller collision space.    I would also add something to the random input to the hash (md5,sha1).  So perhaps add something like username + random bytes.  People can generate a large table from random byte input (a rainbow table) and look for matches.  By doing so they might figure out you are just using random byte combinations of a certain size.  It's not a major security hole, but one you can protect against by not just hashing random characters of the exact same size from a routine.  This is similar to the idea of using a "salt".  

  • Thanks 1

Hey Giz and everyone..  I'm getting somewhere, and have not had time to consider everything you have suggested, yet. Though, this feels like a final hurdle - which is good! The problem i'm having seems like a simple one and i was hoping someone could make me feel better by helping me out. Everything seems fine, but when I login from another browser the existing browser "logs out", or should i say perishes. This I thought may be a good feature as it stops multipul users from, using the same account, though it was pointed out to me that often users have logged in on multi devices, so this proves me wrong.

<?php

session_start();

function setRememberMeToken($pdo, $user_id) {

    // -------------------------------------
    //random_bytes () function in PHP
    $length = random_bytes('25');
    //Print the result and convert by binaryhexa
    $token = bin2hex($length);
    // -------------------------------------
    setcookie("token", $token, time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["token"] = $token;
    setcookie("remember", "true", time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["remember"] = "true";   // set for no-remember

    
    // INsert into DB ("token")

    
    $sql = "UPDATE users SET cookie_token=? WHERE user_id=?";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([md5($token), $user_id]);

    // --------
    
    $stmt = $pdo->prepare("SELECT cookie_token, name FROM users WHERE user_id=?");
    $stmt->execute([$user_id]); 
    $info = $stmt->fetch();

    echo $info['cookie_token'] ."<<<< -- match";
    echo "<br>";
    echo md5($_COOKIE["token"]) ."<<<< -- match";

    //setcookie("token_user", $user_id, time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    //$_COOKIE["token_user"] = $user_id;

    $start_date = date("Y/m/d");  
    $date = strtotime($start_date);
    $date = strtotime("+7 day", $date);
    $to =  date('Y-m-d', $date);

    $sql = "UPDATE users SET cookie_expire=? WHERE user_id=?";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$to, $user_id]);


}


function tokenLoggedIn($pdo) {

    //$user_id= $_COOKIE["token_userid"];
    $_COOKIE["token"];

    $stmt = $pdo->prepare("SELECT user_id, name, cookie_token, cookie_expire FROM users WHERE cookie_token=?");
    $stmt->execute([md5($_COOKIE['token'])]); 
    $info0 = $stmt->fetch();

    //echo "<br>";
    $expireDate = $info0['cookie_expire'];
    //echo "<br>";
    $today = date("Y-m-d");  
    //echo "<br>";
    
    $startdate = new DateTime($today);
    $now = new DateTime();
    $enddate = new DateTime($info0['cookie_expire']);

    if($startdate <= $now && $now <= $enddate) { // between 

            $str1 =  $info0['cookie_token'];
            $str2 = md5($_COOKIE["token"]);
            if($str1 != $str2){
                return false;
                //header("location: login.php");
            }elseif($str1 == $str2)
            {
                return true;
                $_SESSION["username"] = $info0['name'];
                $_SESSION['the_usr_id'] = $info0['user_id'];
                // GOOD!

            } 
    }else{
        echo "No";
    }
// ---------------




}


function setSessionVarables($pdo) {
    $stmt = $pdo->prepare("SELECT user_id, name, cookie_token, cookie_expire FROM users WHERE cookie_token=?");
    $stmt->execute([md5($_COOKIE['token'])]); 
    $user_info = $stmt->fetch();
    //echo md5($_COOKIE['token']);
    //echo $user_info['user_id'] . " // ". $user_info['name'];
    $_SESSION["loggedin"] = true;
    $_SESSION["username"] = $user_info['name'];
    $_SESSION['the_usr_id'] = $user_info['user_id'];
    //echo $_SESSION['the_usr_id'] = $user_info['user_id'];
}
function isRemembered($pdo) {
    if(isset($_COOKIE["remember"])){
        return true;
    } elseif(!isset($_COOKIE["remember"])){
        return false;
    }
}

?>

Conclusion: I need to make it so that a user can log on from different devices without perishing the existing login/s. Plz help. O0 There is a problem with the code, but cannot solve the problem myself.

 

:ninja:

Edited by oz11

ps, i use the folowing code to initialise the functions on each page of my site (index.php, etc.)

 

include 'includes/functions/remember_token.php';  /// WORKING
if (isset($_COOKIE['token'])) { setSessionVarables($pdo); }

and the following for dashboard.php (post login)

include 'includes/functions/remember_token.php';

// ---~ login check ~---

//echo isRemembered($pdo);
//echo "<br>";
//tokenLoggedIn($pdo);
if (isRemembered($pdo) == 0)
{
    if (!isset($_SESSION['loggedin']) OR $_SESSION['loggedin'] != true) {
    
        header("location: login.php");
        exit;
    } 
    echo "good. not remembered but still passes as logged in via sessions";
}
elseif (isRemembered($pdo) == 1) {
    if (tokenLoggedIn($pdo) == false){
        header("location: login.php");
        echo "bad. remembered but not allowed";
        exit;
    } elseif(tokenLoggedIn($pdo) == true) {
        setSessionVarables($pdo);
            $_SESSION["r_u_in"] = true;
        echo "good. remembered and (passes denied/allowed) so logged in";
    }
}

Edit: 

I see the problem is that the token is getting overwritten, pulling the possibility for the previous user to be able to use their own token. So i can only assume/ presume there should be some form of iteration on the following block of code, so its only preformed when a user first logs and sets a "session = true" or something. Then if the user has a "session = true", then the code is non evaluated again..? - Maybe the cookie value could even be in this session?

    $sql = "UPDATE users SET cookie_token=? WHERE user_id=?";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([md5($token), $user_id]);

What do you guys think about this?

Edited by oz11

If you want multi-device support, you need to move your cookie_token field out of your users table and into another table so that you can have multiple active tokens.  For example

create table user_token (
  UserId int not null,
  TokenHash varchar(255) not null,
  Expires datetime,
  primary key (UserId, TokenHash)
);

Whenever you generate a new token, insert a row into that table.  When you need to validate the token, look for it in the table and make sure it's not expired.

 

  • Haha 1
19 hours ago, kicken said:

If you want multi-device support, you need to move your cookie_token field out of your users table and into another table so that you can have multiple active tokens.  For example

create table user_token (
  UserId int not null,
  TokenHash varchar(255) not null,
  Expires datetime,
  primary key (UserId, TokenHash)
);

Whenever you generate a new token, insert a row into that table.  When you need to validate the token, look for it in the table and make sure it's not expired.

 

Had to re write my code due to bug chasing, but works now. Thanks. and thanks everyone! 

 

For anyone still interested here is my functions (still might need some tuning, but ok):

<?php
//include "../../config.php";
session_start();

function setRememberMeToken($pdo, $user_id) {

    //random_bytes () function in PHP
    $length = random_bytes('25');
    $token = bin2hex($length);
    setcookie("token", $token, time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["token"] = $token;
    setcookie("remember", "true", time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["remember"] = "true";   // set for no-remember
    $start_date = date("Y/m/d");  
    $date = strtotime($start_date);
    $date = strtotime("+7 day", $date);
    $to =  date('Y-m-d', $date);

    // --------
    $sql = "INSERT INTO `user_token` (`token_id`, `user_id`, `expires`, `tokenHash`) VALUES (NULL, ?, ?, ?);    ";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$user_id, $to, sha1($token)]);

    echo sha1($token);



}


function getRememberMeCheck($pdo) {

  

    $stmt = $pdo->prepare("SELECT users.name, users.user_id, tokenHash FROM user_token, users WHERE tokenHash = ? 
    AND users.user_id = user_token.user_id    ");
    $stmt->execute([sha1($_COOKIE["token"])]); 
    $db_query = $stmt->fetch();
//echo "good...<hr>";

    echo $str1 =  $db_query['tokenHash'];
    echo "<br>";
    echo $str2 = sha1($_COOKIE["token"]);

    if($str1 != $str2){

        echo "bad";
        //header("location: login.php");
        return false;
    }elseif($str1 == $str2)
    {

        echo $_SESSION["username"] = $db_query['name'];
        echo $_SESSION['the_usr_id'] = $db_query['user_id'];
        // GOOD!
        //echo "goo2222d";
        return true;


    } 
    echo "right on man!";
}




function setSessionVarables($pdo) {

    $stmt = $pdo->prepare("SELECT users.name, users.user_id, user_token.tokenHash FROM user_token, users WHERE tokenHash = ? 
    AND users.user_id = user_token.user_id    ");
    $stmt->execute([sha1($_COOKIE["token"])]); 
    $db_query2 = $stmt->fetch();

    echo "<hr>";
    echo $_SESSION["loggedin"] = true;
    echo $_SESSION["username"] = $db_query2['name'];
    echo $_SESSION['the_usr_id'] = $db_query2['user_id'];
}

function isRemembered($pdo) {
    if(isset($_COOKIE["remember"])){
        return true;
    } elseif(!isset($_COOKIE["remember"])){
        return false;
    }
}
?>

<?php
//setRememberMeToken($pdo, 44);
//getRememberMeCheck($pdo);
//setSessionVarables($pdo);


?>

 

27 minutes ago, oz11 said:
$sql = "INSERT INTO `user_token` (`token_id`, `user_id`, `expires`, `tokenHash`) VALUES (NULL, ?, ?, ?);    ";
$stmt= $pdo->prepare($sql);
$stmt->execute([$user_id, $to, sha1($token)]);

The point of storing the expiration date is so that you can check it when you lookup the token later and reject expired tokens.  You cannot rely on the cookie being deleted by the browser at the requested time, so you must check for yourself if the token is expired or not.

$stmt = $pdo->prepare("
SELECT users.name, users.user_id, tokenHash 
FROM user_token, users 
WHERE 
tokenHash = ? 
AND expires > NOW()
AND users.user_id = user_token.user_id
");
$stmt->execute([sha1($_COOKIE["token"])]); 
$db_query = $stmt->fetch();

 

  • Great Answer 1
1 hour ago, kicken said:

The point of storing the expiration date is so that you can check it when you lookup the token later and reject expired tokens.  You cannot rely on the cookie being deleted by the browser at the requested time, so you must check for yourself if the token is expired or not.

$stmt = $pdo->prepare("
SELECT users.name, users.user_id, tokenHash 
FROM user_token, users 
WHERE 
tokenHash = ? 
AND expires > NOW()
AND users.user_id = user_token.user_id
");
$stmt->execute([sha1($_COOKIE["token"])]); 
$db_query = $stmt->fetch();

 

Ooops. I forgot to add that bit in (it was a late night and i needed sleep, but didn't(but that's a whole different story)..

Should look like this, i believe?

<?php
//include "../../config.php";
session_start();

function setRememberMeToken($pdo, $user_id) {

    //random_bytes () function in PHP
    $length = random_bytes('25');
    $token = bin2hex($length);
    setcookie("token", $token, time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["token"] = $token;
    setcookie("remember", "true", time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["remember"] = "true";   // set for no-remember
    $start_date = date("Y/m/d");  
    $date = strtotime($start_date);
    $date = strtotime("+7 day", $date);
    $to =  date('Y-m-d', $date);

    // --------
    $sql = "INSERT INTO `user_token` (`token_id`, `user_id`, `expires`, `tokenHash`) VALUES (NULL, ?, ?, ?);    ";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$user_id, $to, sha1($token)]);

    echo sha1($token);



}


function getRememberMeCheck($pdo) {

  

    $stmt = $pdo->prepare("SELECT users.name, users.user_id, tokenHash FROM user_token, users WHERE tokenHash = ? 
    AND users.user_id = user_token.user_id    ");
    $stmt->execute([sha1($_COOKIE["token"])]); 
    $db_query = $stmt->fetch();
//echo "good...<hr>";

    echo $str1 =  $db_query['tokenHash'];
    echo "<br>";
    echo $str2 = sha1($_COOKIE["token"]);

    if($str1 != $str2){

        echo "bad";
        //header("location: login.php");
        return false;
    }elseif($str1 == $str2)
    {

        echo $_SESSION["username"] = $db_query['name'];
        echo $_SESSION['the_usr_id'] = $db_query['user_id'];
        // GOOD!
        //echo "goo2222d";
        return true;


    } 
    echo "right on man!";
}




function setSessionVarables($pdo) {

    $stmt = $pdo->prepare("SELECT users.name, users.user_id, user_token.tokenHash, user_token.expires FROM user_token, users WHERE tokenHash = ? 
    AND users.user_id = user_token.user_id    ");
    $stmt->execute([sha1($_COOKIE["token"])]); 
    $db_query2 = $stmt->fetch();

    $today = date("Y-m-d"); 
    $startdate = new DateTime($today);
    $now = new DateTime();
    $enddate = new DateTime($db_query2['expires']);

    if($startdate <= $now && $now <= $enddate) {
        echo "<hr>";
        echo $_SESSION["loggedin"] = true;
        echo $_SESSION["username"] = $db_query2['name'];
        echo $_SESSION['the_usr_id'] = $db_query2['user_id'];
    }else{
        echo "no";
    }
}

function isRemembered($pdo) {
    if(isset($_COOKIE["remember"])){
        return true;
    } elseif(!isset($_COOKIE["remember"])){
        return false;
    }
}
?>

<?php
//setRememberMeToken($pdo, 44);
//getRememberMeCheck($pdo);
//setSessionVarables($pdo);


?>

Thanks everyone.

infact, that one was wrong..

this is right:

<?php
//include "../../config.php";
session_start();

function setRememberMeToken($pdo, $user_id) {

    //random_bytes () function in PHP
    $length = random_bytes('25');
    $token = bin2hex($length);
    setcookie("token", $token, time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["token"] = $token;
    setcookie("remember", "true", time() + (86400 * 7), "/");  // <--- month in seconds (per day x 30)
    $_COOKIE["remember"] = "true";   // set for no-remember
    $start_date = date("Y/m/d");  
    $date = strtotime($start_date);
    $date = strtotime("+7 day", $date);
    $to =  date('Y-m-d', $date);

    // --------
    $sql = "INSERT INTO `user_token` (`token_id`, `user_id`, `expires`, `tokenHash`) VALUES (NULL, ?, ?, ?);    ";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$user_id, $to, sha1($token)]);

    echo sha1($token);



}


function getRememberMeCheck($pdo) {

  

    $stmt = $pdo->prepare("SELECT users.name, users.user_id, expires, tokenHash FROM user_token, users WHERE tokenHash = ? 
    AND users.user_id = user_token.user_id    ");
    $stmt->execute([sha1($_COOKIE["token"])]); 
    $db_query = $stmt->fetch();
    
//echo "good...<hr>";

    echo $str1 =  $db_query['tokenHash'];
    echo "<br>";
    echo $str2 = sha1($_COOKIE["token"]);

    $today = date("Y-m-d"); 
    $startdate = new DateTime($today);
    $now = new DateTime();
    $enddate = new DateTime($db_query['expires']);

    
    if($str1 != $str2){

        echo "bad";
        //header("location: login.php");
        return false;
    }elseif($str1 == $str2)
    {

        if($startdate <= $now && $now <= $enddate) {
            echo $_SESSION["username"] = $db_query['name'];
            echo $_SESSION['the_usr_id'] = $db_query['user_id'];
            // GOOD!
            echo "---> goo2222d <---";
            return true;
        }


    } 
    echo "right on man!";
}




function setSessionVarables($pdo) {

    $stmt = $pdo->prepare("SELECT users.name, users.user_id, user_token.tokenHash, user_token.expires FROM user_token, users WHERE tokenHash = ? 
    AND users.user_id = user_token.user_id    ");
    $stmt->execute([sha1($_COOKIE["token"])]); 
    $db_query2 = $stmt->fetch();


        echo "<hr>";
        echo $_SESSION["loggedin"] = true;
        echo $_SESSION["username"] = $db_query2['name'];
        echo $_SESSION['the_usr_id'] = $db_query2['user_id'];
}

function isRemembered($pdo) {
    if(isset($_COOKIE["remember"])){
        return true;
    } elseif(!isset($_COOKIE["remember"])){
        return false;
    }
}
?>

<?php
//setRememberMeToken($pdo, 44);
//getRememberMeCheck($pdo);
//setSessionVarables($pdo);


?>

edited the wrong block as i was rushing.

Do my random numbers/tokens look ok from a security standpoint?

Edited by oz11

Your code can be simplified in many ways.  See the comments in the refactored code below.

<?php
function setRememberMeToken($pdo, $user_id) {
    //$length wasn't a great name and is an unnecessary variable.
    $token = bin2hex(random_bytes('25'));

    $expirationDate = time() + (86400 * 7); // <-- 7 days later (make sure your comments are accurate)
    setcookie("token", $token, $expirationDate, "/");
    $_COOKIE["token"] = $token;

    //$_COOKIE['remember'] is unnecessary, just get rid of it
    //--deleted

    //You calculated your expiration timestamp above already, no need to do it again.
    $to = date('Y-m-d', $expirationDate);

    //Assuming token_id is an auto increment column, you can just omit it from the insert.
    $sql = "INSERT INTO `user_token` (`user_id`, `expires`, `tokenHash`) VALUES (?, ?, ?);";
    $stmt= $pdo->prepare($sql);
    $stmt->execute([$user_id, $to, sha1($token)]);
}


function getRememberMeCheck($pdo) {
    //I find spacing out your queries makes them easier to read and understand.
    $stmt = $pdo->prepare("
    SELECT users.name, users.user_id
    FROM user_token, users 
    WHERE 
        tokenHash = ? 
        AND expires > NOW()
        AND users.user_id = user_token.user_id
    ");
    $stmt->execute([sha1($_COOKIE["token"])]); 
    $db_query = $stmt->fetch();
    
    //Your token and expiration date are validated as part of the query
    //All you need to do is check if you got a result or not.
    if (!$db_query){
        //If you didn't get a result, either the token is invalid or it has expired.
        //header("location: login.php");
        return false;
    }


    //Otherwise, if you did get a result, the token is valid.
    $_SESSION["loggedin"] = true;
    $_SESSION["username"] = $db_query['name'];
    $_SESSION['the_usr_id'] = $db_query['user_id'];
    return true;
}



//This method seems to just be a copy of the method above, why does it exist?
//The only difference is $_SESSION["loggedin"] = true; which you could just do above.
//function setSessionVarables($pdo) {
//...
//}
//--deleted


function isRemembered() {
    //Instead of a separate remember cookie, just check if the token cookie exists.
    //if ($whatever){ return true; } else { return false} can be simplified to just return $whatever
    return isset($_COOKIE['token']);
}

 

Edited by kicken
  • Thanks 1
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.