
Originally Posted by
ice2kewl
Hello,
I'm relatively new to PHP. Currently I'm using md5() to hash and store passwords. Something like:
Code:
$salt = 'SomeSaltString'; //fixed salt
$password = 'SomePassword';
$pass = md5($salt . $password);
This might have been a good technique a few years ago but nowadays it is possible to crack such passwords on cheap hardware. The main problem with this technique is that hashing to md5 (or any other hash) is very fast and if your algorithm is fast then brute force attack can be performed fast. Here is a good article about cracking passwords with modern GPUs: http://www.troyhunt.com/2012/06/our-...o-clothes.html

Originally Posted by
ice2kewl
According to the PHP manual, crypt() with blow fish is the way to go [unless you think my md5() hashing method above is sufficient]:
Yes, use blowfish. The main advantage of this algorithm is that you can adapt its 'cost' - how many hashing iterations will be done and in this way how much the process will be slowed down. If your algorithm is slow then it may take too much time for a potential cracker to bother with brute forcing.

Originally Posted by
ice2kewl
1]. $2a indicates strength level?
No, $2a$, $2x$ and $2y$ all indicate that blowfish should be used. Generally, $2a$ is fine but there was some weakness discovered in PHP versions earlier than 5.3.7 so $2x$ and $2y$ were introduced. If you use 5.3.7 or later then simply use $2y$, otherwise use $2a$.

Originally Posted by
ice2kewl
2]. $07 something to do with round trips? Please elaborate further on this...
This is the cost factor. The higher the number the more hash iterations will be performed and the longer the process will take. Write a small test script that will measure how much time crypt() will take to execute and adjust the cost factor to find the desired balance. I'd say if it takes somewhere between 0.1 and 0.5 seconds then it's fine. Later as your site is moved to faster hardware you can always increase the cost factor. I have found that on my shared hosts 09 or 10 is good.

Originally Posted by
ice2kewl
3]. StrThatIs21Characters$ - salt needs to be 22 chars in length including the $. Should this be a fixed salt?? I'm getting conflicting info on this...
No, this string is not 21 characters plus $, it's 22 characters and $ is not required at the end. As the manual says:
22 digits from the alphabet "./0-9A-Za-z"
This is the random salt that you should generate.

Originally Posted by
ice2kewl
4]. What part of the output should be stored in the database [in the password column]?
Just store the whole output of the crypt function. No need to store the salt separately since the salt is included in the output.

Originally Posted by
ice2kewl
5]. What data type best suits the password column? Perhaps nvarchar?
Yes, varchar is fine. I don't know SQL Server so I don't know about nvarchar, but any variable-length column capable of storing ascii string data will be fine. No need for any unicode or other encodings here.

Originally Posted by
ice2kewl
6]. How should a login attempt be verified when using this method?
First, this is what I use to hash the password:
PHP Code:
$random_str = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM);
$salt = substr(base64_encode($random_str), 0, 22);
$salt = str_replace('+', '.', $salt);
$hashed_password = crypt($password, '$2y$09$'.$salt);
// $hashed_password is what should be stored in the db
mcrypt_create_iv() returns binary data and is a very good simple function to get a random string for the salt because it provides better randomness than rand() and mt_rand(). base64_encode() gives us almost the right range of allowed characters for the salt, we only need to change '+' to '.'.
And this is how I check if entered password is correct:
PHP Code:
if ($hashed_password_in_db === crypt($password_entered_by_user, $hashed_password_in_db)) {
// password correct
// ....
}
As you can see the result of crypt can be used as a salt hence no need to store the salt separately. This method also allows you to change the cost factor for your passwords and even change crypt() hashing algorithms and still you can validate all passwords in the same way.

Originally Posted by
kduv
I would suggest using PHPass for password hashing. It uses bcrypt and automates hashing, salting, and stretching of passwords. The script is at:
http://www.openwall.com/phpass/
I don't see why use and learn an external library for something that can be easily and efficiently achieved with a few lines of native PHP code, unless you want compatibilty with older PHP versions and installations where crypt algorithms are limited, but for any new PHP version I don't think it's worth it.
Bookmarks