Rajohan
Rajohan

Reputation: 1415

PHP remember me cookies

I'm trying to make a remember me function for a user login. I think i have the basics covered.

If the auth_tokens table should for some reason be leaked, impersonation is prevented by not having the cookie value equal to the table values (base64_encode/base64_decode). (They can be decoded and used but its at least a bit more work to steal an account)

No user information is stored in the cookie.

When a user successfully logs in with the remember me cookie, a session is set to prevent the database from getting useless requests.

A new selector, token and expire date is crated at each login

So my question now is, are there a way to prevent someone from stealing a cookie value and then creating the remember me cookie to successfully log in as that user?

And is the way I'm using session's secure or is it possible for someone to set these to what ever value they would want?

And my last question. Should the USER_ID in the AUTH_TOKENS table also be encoded to make it harder guessing what user the tokens belong to? If so how would I then select the correct user id from the user table when needed.

if(auto login) {

    $expire = time() + 3600 * 24 * 30; // Cookie expire time
    $expire_encoded = base64_encode($expire); // Expire encoded

    $token_encoded = base64_encode(bin2hex(random_bytes(32))); // 32chars token encoded
    $token = base64_decode($token_encoded); // 32 chars token decoded

    $selector_encoded = base64_encode(bin2hex(random_bytes(16))); // 16 chars token encoded
    $selector = base64_decode($selector_encoded); // 16 chars token decoded

    $userid = 1; // User id
    $value = "$selector|$token"; // Cookie value

    setcookie('remember', $value, $expire, '/', $_SERVER['SERVER_NAME'], true); // Set cookie

    // Insert to db (not an actual function, just for this post. I'm using bind parm)
    insert_db(SELECTOR = $selector_encoded, USER_ID = $userid, TOKEN = $token_encoded, EXPIRES = $expire_encoded, IP = ip, date = date/time)

}

if((isset($_COOKIE['remember']) && (!isset($_SESSION['logged_in']))) {

    $tokens = explode('|',$_COOKIE['remember']);

    $selector = base64_encode($tokens[0]);
    $token = base64_encode($tokens[1]);

    // Select from db (not an actual function, just for this post. I'm using bind parm)
    $row = select_from_db(WHERE SELECTOR = $selector AND TOKEN = $token);

    if(mysqli_num_rows($row) === 1){

       // User logged in
       $_SESSION['logged_in'] = true;
       $_SESSION['user_id'] = $row['USER_ID'];

       // Generate new selector, token and expire date and insert to db

    } else {

      // User not logged in

    }

}

My auth_tokens table looks like this

    +------------------+
    | AUTH_TOKENS      |
    +------------------+
    | ID               |
    | SELECTOR         |
    | USER_ID          |
    | TOKEN            |
    | EXPIRES          |
    | IP               |
    | DATE             |
    +------------------+

Upvotes: 1

Views: 1725

Answers (1)

Kerkouch
Kerkouch

Reputation: 1456

The remember me token should not be accessible via JavaScript, and should not be transmitted over non secure requests. So if this is the case, how someone can have access to the tokens, if he have access to your database then that's another problem.

So to make a cookie transmitted only over HTTPS requests and hide it from been accessed via JavaScript, you should replace this line in your code

setcookie('remember', $value, $expire, '/', $_SERVER['SERVER_NAME'], true);

with this one:

setcookie('remember', $value, $expire, '/', $_SERVER['SERVER_NAME'], true, true);

For more details read the manual setcookie

Upvotes: 1

Related Questions