3
\$\begingroup\$

I'm trying to make a safe "remember me / auto login" function on my site and as I'm just a hobby programmer I would like someone professional to take a look at my code this far. This site will probably never see the light of day I'm just doing this because I find it fun and learning, but I still like to do it correct. I have read this.

Login.php

$query = $db->prepare('SELECT id, username, password FROM users WHERE username = ? OR email = ?');
$query->execute(array($_POST['username'], $_POST['username']));
$row = $query->fetch();

if ($row and password_verify($_POST['password'], $row['password'])) {

    // Remember?
    if (isset($_POST['remember'])) {

        $selector = base64_encode(random_bytes(9));
        $authenticator = random_bytes(33);

        setcookie('remember', $selector.':'.base64_encode($authenticator), time() + 864000);

        $query = $db->prepare('INSERT INTO auth_tokens (selector, token, userid, expires) VALUES (?, ?, ?, ?)');
        $query->execute(array(   $selector, hash('sha256', $authenticator), $row['id'], date('Y-m-d\TH:i:s', time() + 864000)  ));  
    }

    $_SESSION['userid'] = $row['id'];
    $_SESSION['username'] = $row['username'];

    exit(header('Location: /'));
}

This is my logout:

session_destroy();

if (!empty($_COOKIE['remember'])) {
    setcookie('remember', '', time() - 1000);
    $db->exec('DELETE FROM auth_tokens WHERE userid = '.$_SESSION['userid']);
}

exit(header('Location: '.SITE_URL));

And this is my code in index.php to check if the user has the cookie and log them in:

if (empty($_SESSION['userid']) && !empty($_COOKIE['remember'])) {

    list($selector, $authenticator) = explode(':', $_COOKIE['remember']);

    $query = $db->prepare('SELECT * FROM auth_tokens WHERE selector = ?');
    $query->execute(array($selector));
    $row = $query->fetch();

    if (hash_equals($row['token'], hash('sha256', base64_decode($authenticator)))) {
        $_SESSION['userid'] = $row['userid'];
    }
}

One thing I need to do is check if the cookie has expired and log them out, but other than that what do you think? Am I missing something?

\$\endgroup\$
  • \$\begingroup\$ also, i should probably check if the row exists is auth_tokens. in the last code I posted. because if i were to truncate auth_tokens and some users still have the cookie an error will display about hash_equals \$\endgroup\$ – Arvid Ingemarsson Feb 5 '17 at 15:42
2
\$\begingroup\$

You are doing good. You are referencing a good example. The flow will be as below:

  1. Once the user logs in and have checked "remember me", set the cookie with a unique token for user.

  2. Next time when the user comes back, check the cookie with the token value in DB.

  3. If it matches, allow the user to login.

  4. If the token is missing redirect to login.

Ref: http://jaspan.com/improved_persistent_login_cookie_best_practice

\$\endgroup\$
0
\$\begingroup\$

When a user somehow gets to know your selector and uses it but the token doesn't match, then you need to delete the data in "token" field

Because, if someone else is trying to access in your account with the correct selector but with wrong token then, your account will be immediately secured....

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.