Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Designing a secure auto login cookie system in PHP

I want to have an auto login option check for a user. Basically that means a cookie will be stored on the client side.

Now the question is, how do I make it secure so the cookie will can not be spoofed/modified.

One of my friends suggest having a db table that stores the session_id, user's ip, browser info, etc and then compare it all that information once a user goes to the website again.

I feel like having a separate table for that is a bit too much trouble. Is there another way to do it? Maybe with tokens or something like that?

like image 785
CodeCrack Avatar asked Sep 29 '11 02:09

CodeCrack


People also ask

How can we implement Remember me using PHP?

It means that if the users access the web application later, they need to log in again. The remember me feature allows the users to save their logins for some time, even after closing the web browsers. To implement the remember me feature, you'll use cookies with expiration times in the future.

What is cookies How do you create cookies in PHP?

A cookie is often used to identify a user. A cookie is a small file that the server embeds on the user's computer. Each time the same computer requests a page with a browser, it will send the cookie too. With PHP, you can both create and retrieve cookie values.

How do you keep user state with cookies?

HTTP is a stateless protocol. This means that user data is not persisted from one Web page to the next in a Web site. One way to maintain state is through the use of cookies. Cookies store a set of user specific information, such as a reference identifier for a database record that holds customer information.


2 Answers

The more secure you want this infamous cookie, the more trouble it's going to be for you. If your users should be particularly secure, you will have to go with the most troublesome approach.

You should only accept this cookie with https if you want to be as secure as possible. If the cookie is accepted over http, it can be sniffed and stolen.

I would recommend that the cookie have no user data at all (a token, as you suggested). This will, unfortunately, require another table. When a user logs in and chooses "keep login," create an entry in this table. The entry can be any meaningless value (such as md5(uniqid('', true));. This token can be unique in the DB and mapped to a user's ID.

When a user visits your website, you can check the value of that cookie and get the user it belongs to and log them in. At this point, you destroy the old token and create a new one. "Destroy" can mean many things. You can delete it from the DB entirely or have a flag that disables the token. You may want to allow the same token to be used multiple times in case the cookie is received but the authentication doesn't go through for some reason, but I think this is insecure. You may also want to store the timestamp of the token and only accept it if it's been some limited period of time (30 days for example).

As your friend points out, you can store other information such as user agent, IP address, etc., but these may change even with the same browser being used (especially with mobile) and if a user's persistent login is not accepted because of this, it could be jarring and inconvenient to them.

If you really don't want to create another table, then you will have to store some way to acquire the user's ID from the cookie value. This is less secure.

like image 75
Explosion Pills Avatar answered Sep 18 '22 15:09

Explosion Pills


For most auto-logins I know, there is a separate table to store logged-in sessions. Each auto-login session is assigned a hashed key as an identifier, the key is considerably long and virtually not possible to spoof. If you don't want users to be logged in cross-ip even with a valid code, try this.

function gen_uniqueIdent($length=32){
    $alphabet = str_split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789');
    $key = '';
    for($loop=0;$loop<$length;$loop++){
        $i = mt_rand(0,count($alphabet)-1);
        $key.= $alphabet[$i];
    }
    return $key;
}

Assign this value to the user cookie upon login. Then store this into the db:

function save_ident($identFromFunctionAbove,$authenticated_user_id){
    //hash this with something unique to the user's machine
    $hashed = md5($identFromFunctionAbove . $_SERVER['REMOTE_ADDR']);
    /** Some actions to remember this hash **/
}

save that into a database correspinding with a user identity like user_id.

Now upon validation of the user cookie, you can simply:

function validateCookie(){
    $ident = $_COOKIE['yourCookieName'];
    $hashed = md5($ident . $_SERVER['REMOTE_ADDR']);
    /** Check if this hashed value exists in db, if it does, authenticate user **/
}

You'll also need to remove the sessions after they expire or the user explicitly logs out.

Of course this is very simple, and doesn't account for md5 or ident collisions. Still, getting two 32-character random generated string to be the same as one previously generated is pretty slim a chance.

like image 44
jabbany Avatar answered Sep 19 '22 15:09

jabbany