Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a relatively secure way of using a login cookie?

I was wondering what the safest way of a cookie login is? If you just store the pass(encrypted with salt) and username in the cookie and validate it against the user table, a potential attacker can steal a cookie and login. People normally don't check there 'last time online'.

So is there a better way for the 'remember me cookie'? IP isn't a good option, is it? (Some machines change IP all the time).

like image 386
SuperSpy Avatar asked Jan 23 '11 11:01

SuperSpy


People also ask

How do you securely use cookies?

You can ensure that cookies are sent securely and aren't accessed by unintended parties or scripts in one of two ways: with the Secure attribute and the HttpOnly attribute. A cookie with the Secure attribute is only sent to the server with an encrypted request over the HTTPS protocol.

How are cookies used for login?

Persistent cookies are implemented by many websites as a "remember me" checkbox on the login page; when selected, a persistent cookie is sent to the client browser upon login. The user authentication cookie model gives users the convenience of not having to enter login credentials every time a site is revisited.

What makes a cookie secure?

The cookie will only be added to connections such as HTTPS (HTTP over Transport Layer Security (TLS)). Note that it is up to the browser to decide what it considers 'secure'. Typically the browser considers it secure if the protocol makes use of the secure-transport-layer.

Are cookies safe in HTTPS?

Cookies are sent within the HTTP header. Thus they are as secure as the HTTPS connection which depends on a lot of SSL/TLS parameters like cipher strength or length of the public key. Please keep in mind that unless you set the Secure flag for your Cookie, the Cookie can be transmitted over an unsecure HTTP connection.


2 Answers

I think I've found a clever solution!

Advantages of this (complicated?) script:

  • When the user successfully logs in with Remember Me checked, a login cookie is issued in addition to the standard session management cookie.[2]
  • The login cookie contains the user's username, a series identifier, and a token. The series and token are unguessable random numbers from a suitably large space. All three are stored together in a database table.
  • When a non-logged-in user visits the site and presents a login cookie, the username, series, and token are looked up in the database.
  • If the triplet is present, the user is considered authenticated. The used token is removed from the database. A new token is generated, stored in database with the username and the same series identifier, and a new login cookie containing all three is issued to the user.
  • If the username and series are present but the token does not match, a theft is assumed. The user receives a strongly worded warning and all of the user's remembered sessions are deleted.
  • If the username and series are not present, the login cookie is ignored.

I've made a table in the database with the following information:

    session | token | username | expire

The remember me cookie will have this setup:

    $value = "$session|$token|$userhash"; //Total length = 106
  • Session will be a string of 40 (sha1) characters.
  • Token will be a string of 32 (md5) characters.
  • Userhash in the cookie will be a string of 32 (md5 of username) characters.
  • Username in the database will be the normal username.
  • Expire will be now + 60 days.

The script:

if(isset($_SESSION['check']) || $_SESSION['check']){
    //User is logged in
}else if(isset($_COOKIE['remember']) && strlen($_COOKIE['remember'])==106){
    //THERE is a cookie, which is the right length 40session+32token+32user+2'|'
    //Now lets go check it...
    conncectdb(); //Sets connection
    //How do I protect this script form harmful user input?
    $plode = explode('|',$_COOKIE['remember']);
    $session = mysql_real_escape_string($plode[0]);
    $token = mysql_real_escape_string($plode[1]);
    $userhash = mysql_real_escape_string($plode[2]);
    $result = mysql_query(" SELECT user 
                FROM tokens 
                WHERE session = '$session' 
                AND token = '$token'
                AND md5(user) = '$userhash';")
    if(mysql_num_rows($result)==1){
        //COOKIE is completely valid!
        //Make a new cookie with the same session and another token.
        $newusername = mysql_result($result,0,0);
        $newsession = $session;
        $newtoken = md5(uniqid(rand(), true));
        $newuserhash = md5($username);
        $value = "$newsession|$newtoken|$newuserhash";
        $expire = time()+4184000;
        setcookie('remember', $value, $expire, '/', 'www.example.com', isset($_SERVER["HTTPS"]), true);
        mysql_query("   UPDATE tokens 
                SET token='$newtoken', expire='$expire'
                WHERE session = '$session' 
                AND token = '$token'
                AND md5(user)='$userhash';");
        //Set-up the whole session (with user details from database) etc...
    } else if(mysql_num_rows(mysql_query("SELECT user FROM tokens WHERE session = '$session' AND md5(user) = '$userhash';"))==1)){
        //TOKEN is different, session is valid
        //This user is probably under attack
        //Put up a warning, and let the user re-validate (login)
        //Remove the whole session (also the other sessions from this user?)
    } else {
        //Cookie expired in database? Unlikely...
        //Invalid in what way?
    }
} else {
    //No cookie, rest of the script
}

Advantages of the script:

  • Multiple login. You can create new sessions for each computer you're on.
  • Cookie and database will stay clean. Active users renew there cookie every login.
  • The session check at the beginning ensures that the database will not get useless requests.
  • If an attacker steals a cookie, it gets a new token, but not a new session. So when the real user visits the website with the old(invalid) token but WITH a valid user-session combination the user gets a warning of the potential theft. After re-validating by logging in a new session is created and the session the attacker holds is invalid. The re-validating ensures the victim really is the victim, and not the attacker.

Reference: http://jaspan.com/improved_persistent_login_cookie_best_practice

like image 189
SuperSpy Avatar answered Oct 05 '22 22:10

SuperSpy


Such a “remember me” feature is always an additional security risk.

Because just like in a session you only have one identifier that suffices not just to identify a user (Who is it?) but also to authenticate that user (Is it really him/her?) without doing an actual authentication.

But in opposite to a session that has (or should have) just a short life time (mostly less than an hour) and the identifier is (or should be) changed periodically (time based and on necessity due to authenticity/authority state changes), a “remember me” identifier is valid for days if not even for months or years! And this long validity period poses an additional security risk.

So before asking how to implement such a “remember me” feature, you should ask yourself if you really want that additional security risk. That mainly depends on the assets that your application has and what purpose the authentication has and if you want to take the risk of impersonations/identity thefts that the “remember me” feature poses.

If so, make sure to provide basic security by using HTTPS and set the HTTPOnly flag and the secure flag in your cookies. Then you could do the following to build such a “remember me” feature:

  • Authentication request
    If the user authenticated via HTTPS and set the “remember me” option, generate a random remember me token, store it on the server side in a “remember me” database, and set the remember me cookie with the secure flag with that value. Then start a new session and set a remember me flag.

  • Any other request

    1. If there is no current session, redirect to the remember me page via HTTPS that checks whether there is a remember me cookie. If there is a remember me token and it is valid, invalidate it, generate a new one, store it in the “remember me” database, set a cookie with that new token and create a new session with the remember me flag set. Otherwise redirect to the login page.
    2. If the current session is invalid (make sure to use a strict session invalidation), redirect to the remember me page via HTTPS if the remember me flag is set; otherwise redirect to the login page.

With this the authentication is secured via HTTPS, both the initial authentication and the “remember me” authentication. And the user is only authentic during the current session; if it expires, the user has to re-authenticate either by using the remember me token or providing his/her login credentials. And as the remember me tokens are stored in the database, the user can invalidate any existing remember me token.

like image 29
Gumbo Avatar answered Oct 05 '22 22:10

Gumbo