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).
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
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
- 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.
- 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.
Most popular ways:
Many scripts uses some kind of session tracking. When the user first visits the website, it generates a unique random ID for the user and store session information in the server and the ID in the cookie. The server then identifies the user using the unique ID (called session ID). The information associated with the session ID can be seen only by the server. PHP uses this by default,
Some stores the user data in the cookie itself, but with a HMAC signature using a secret string as a key. The script discards the cookie if the signature doesn't match. This way, the server does not have to keep the session data on the server. The user sees what's in the session by looking at the cookie, so you should not store sensitive data in it. Just the user ID (and possibly login time and cookie expiry time) should be enough. Though the user can see what's in the session info, the signature in the cookie makes sure that the user cannot modify the session data himself.
These ways provide some security, that the user can't tamper with the session data, but it doesn't protect the user from eavesdropper. They can always use a packet sniffer and steal a session from any open WiFi network. Some apps do rely on the user IP but it doesn't matter if the attacker is in the same network. Some apps rely on User-Agent, but there will be problems when the user updates their browser or import data from another browser.
If you are really concerned about security, then use HTTPS.
Also read this article, especially the section called How do website operators fix the problem?