Efficient way to protect a password on a database
The most common way to protect a password in a database is to hash it with a md5 function (for example).
Why to do this ? If the database is stollen (an sql injection exploit for example), you can gurantee to your members that their password could not be retrieved.
That's important not only to protect your own website, but to protect the member privacy coz they often use the same password on many services.
So the question is, with a md5 is the password secured ? And the answer is NO :(
For example :
mylongpassword --> 02e8ca66d899fe35ecb9825ff644bba7
(should be secure)
And take a look at :
http://www.md5rainbow.com/02e8ca66d899fe35ecb9825ff644bba7
You may think WTF (or something like that) ... the reason of that the password was break is a technique called the rainbow table, that consist to generate a brute-force table of all password<->md5 possibilities.
What is the solution ?
There is some ways to improve the password security :
Salt the password : by salting the password, it will be too long to be bruteforced into a rainbow table
Use a more slow hashing algorithm : if the algorithm is slow, the rainbow table will be smaller and will take more time to be generated
example :
md5 : 6,8ms
sha256 : 19ms
sha512 : 45ms
- Generate a random salt for every account - the hacker will never can generate a rainbow table for each account just to find only one password.
I've started a little handy function available on Gist :
https://gist.github.com/3419581
<?php
/**
* This function is distributed under the MIT Open Source License.
* @author Ioan CHIRIAC
* @link https://github.com/ichiriac
*/
function generate_password($password, $salt = 'your-secret-salt', $algo = 'sha256')
{
// split the password
$password = str_split($password, ceil(strlen($password)/2));
// make a variable length salt
$salt =
$password[0]
. hash($algo, $password[0])
. $salt
. hash($algo, $password[1])
. $password[1]
;
// split the salt into 2 parts
$salt = str_split($salt,ceil(strlen($salt)/2));
// generating the hash with variable length generated salt
return hash(
$algo,
$salt[0]
. $password[0]
. $salt[1]
. $password[1]
);
}
Usage :
echo generate_password('test', 'secret', 'sha256');
Advantages :
This function is safe from generated rainbow tables (even with a blank salt)
It costs 3x times more to generate a rainbow table (using 3 hash functions)
The salt is hidden from hashes (makes it much harder to generate a rainbow table without knowing the generator algorithm)
Written by Ioan CHIRIAC
Related protips
4 Responses
This is a pretty thorough and up to date tip. Nice job!
Nice work - PHP 5.5 should put most of these password hashing issues to bed with the new in-built password hashing API.
Very helpful tip :)
Thank you!
I highly recommend using blowfish/bcrypt versus MD5 or SHA. Unlike the other two, bcrypt is designed to be inefficient, which is what you want for password hashing. While hashing a single password (such as when you set a new password, or compare against a stored value to authenticate) is still relatively fast, with bcrypt, hashing a large number of passwords (such as creating a rainbow table) is going to be many orders of magnitude slower than it would be with MD5 or SHA.
Additionally, bcrypt is tunably complex... You can specify the number of iterations bcrypt should use.