How to improve my user login scheme

2019-03-31 13:57发布

问题:

Question is easy and basic. I've been working with PHP sessions for years and I always managed user login/logout this way:

  1. Start session (session_start() call).
  2. Login: Store a value in the session (i.e. $_SESSION["user_id"] = 34).
  3. Check user logged: Check session value (i.e. isset($_SESSION["user_id"])).
  4. Logout: destroy session (session_destroy() call and unset($_SESSION["user_id"])).

This scheme has worked for me with very easy applications, but now I'm working in a bigger application and this approach is a bit problematic. For instance, I'm not able to implement the "remember" checkbox in the login box, because I'm able to set a bigger session cookie expiration date, but the session ends sooner ($_SESSION["user_id"] not set).

The point is, how can improve this scheme or which is the standard scheme to manage user sessions in PHP?

回答1:

Your approach is very fine for normal sessions. The problematic bit here is a "remember me" functionality, which needs to be handled differently than a normal session.

A common way to implement that functionality is to store a second cookie with a far expiration date and put the user ID plus a secure hash in it. You need the user id or some other identification to detect which user comes back, but you also need the secure hash to be sure that the cookie is the one that your web app set and has not been crafted manually. If you do not have a secure hash, people can sent a self-built cookie with the user ID and automatically get logged in.

So the secure hash needs to contain information that only your web app knows about, i.e. the user creation date.

You might want to do it like this:

$cookieValue = (int)$user->id . ':' . md5($user->creationDate . '/' . $user->passwordHash);

Since neither creationDate nor passwordHash change, you can verify the validity of the secure hash when the user tries to login via cookie. When the user changed his password, the password hash changes and the user needs a new cookie - which is very fine in my eyes, since people who stole the cookie would also be logged out.

If you want additional security, use another value for hash creation, i.e. a special cookie hash that you store along with the other user data. You can create it completely randomly and should change it whenever the user logs in:

$randomValue = md5(time() . rand() . $user->passwordHash);
$user->setCookieValue($randomValue);
$cookieValue = (int)$user->id . ':' . $randomValue;

Now when logging in:

list($userId, $hash) = explode(':', $cookieValue);
$user = loadUser($userId);
if ($user instanceof User && $user->cookieValue == $hash) {
    //user logged in
    //generate and set new cookie value
} else {
    // handle invalid persistent cookie
}


回答2:

Easy, just change your code as follows:

  1. See if $_SESSION["user_id"] contains a value
  2. If not, see if cookie contains real user data, if so, store in session and login