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