I am using 2 variables in cookie(7 day expiration) which is user id and hash. Hash is sha1 encode of user agent and user id. In this case some hacker can login who is know stolen cookie's browser. Which way should i follow or which practise is best for remember me security problems ?
Personally, I create a random hash and store it in a "remember me" table. The table also has the user agent, user id and the IP address. I check both every time I re-login the user from the remember-me function. And if the user manually logs out, I simply remove that row from the table. Then if they login again, it creates a new random hash. There's really no way to combat someone sniffing packets with a remember me system (unless you use secure cookies with the HTTPS only flag set). So use a secure connection with HTTPS-only cookies. If you can't, then at least make the the hash random so if it is discovered you can at least generate a new hash to kill that login...
You can eventually use sessions to store user status. But holding session so long cause same problem, when session id will be stolen. You may join cookie informations with some other - like browser or IP address, but it would cause a problem, when user don't have static IP.
Anyway, holding a session id is safer that just putting user's sha1 endoded password to cookies.
HMAC
I usually do this way so I've nothing to store on the server side on databases or similar.
You have to generate random string that becomes your "secret key" and that you have to store on the server side (probably in a config php script as a constant) and you have never to tell to anyone. I'll call this secret key SECRET_KEY
.
Then your cookie has to set two values:
USER_ID
: The user id of the user which will get the automatic loginHASH
: A secure cryptographic hash ofUSER_ID
andSECRET_KEY
. So, for example,md5(USER_ID . "-" . SECRET_KEY)
. (Something different than md5, such as sha1 or sha256 is preferred).
So your final cookie could be: USER_ID:HASH
.
Then, when you have to check if a cookie is a genuine remember me cookie, you have to do so:
function isCookieGenuine($cookie_value) {
list($value, $hash) = explode(':', $cookie_value, 2);
if (md5($value . "-" . SECRET_KEY) == $hash)
return true;
else
return false;
}
The point is that only you can generate an hash that passes this check because the hash needs not only the USER_ID
but also the SECRET_KEY
that is unknown by anyone other than the server! :)
As noted in the comments you can do this by using the hash_hmac
function in PHP >= 5.1.2: http://us.php.net/manual/en/function.hash-hmac.php
While you can hash a user_id and secret_key, anyone who intercepts this cookie can log in to your application. In addition to this, you can make it so that your remember me cookies go stale very quickly. No one likes a stale cookie.
You can store the time stamp of each user's last visit in your database and in the cookie. Each time you read the cookie to log the user in, you check to see that both timestamps match. If they don't, deny the user. If they do, update the timestamps.
Using this method, any time your user returns to your site, all old cookies go stale. A hacker that has intercepted a cookie now has a worthless stale cookie because he does not know the exact time stamp in the current cookie. Of course, the hacker can use a fresh cookie as much as he wants until the user logs back in.
//check for cookie
if(isset($_COOKIE['remember_me'])) {
// get hash and time stamp from cookie
$hash = substr($_COOKIE['remember_me'],0,40);
$last_visit = substr($_COOKIE['remember_me'],41);
// query your db with $hash and $last_visit
// if hash and time stamp match up
// log in
// store the current time stamp in a variable to use for both
$time = date("Y-m-d H:i:s");
// update the time stamp in your cookie
$cookie = $pass . "-" . $time;
setcookie('remember_me', $cookie, time()+60*60*24*100, '/');
// update the time_stamp in your database
else {
// remove the remember me cookie
setcookie('remember_me', '', time()-42000, '/')
}
This method offers a small amount of security, and should certainly be used along side methods proposed in other answers. A hashed key should be stored in the cookie. A remember me cookie cannot be perfectly secure, so password re-entry should be required for any additional access to highly sensitive data or application features.
I also recommend naming your cookie something besides 'remember_me' to make it a little harder to find. While it does not add much security, if any, naming your cookie 'ht33424' takes just as long as naming it 'remember_me' or 'hack_me'.
You can simlply set the expiry date as now plus a year on the cookie, but then have an enter password field in all sensitive areas, much like the implementation amazon uses. A hijacked cookie will grant access but to purchase or modify anything personal requires password to be re-entered.
The problem with 'remember me' tables is that if a hacker can gain access to this table he can create and login to as many accounts as he wants. You can argue it strengthens security of a remember me feature, but it needs to be weighed in with the risks of softening knee areas of security.