PHP’s approach to password hashing has quite a history. These methods still litter the tutorials and guide new developers down dangerous paths. Let us take a look at the history so you know where you stand. Even though this post is for PHP, this history may still affect you.
Bad: Raw Password Storage
The first method was just to store the user’s password in plain text just like the user entered it. It was easy; the user would enter their password, and you would just compare the two passwords. If they matched, you were done.
The Issue: If a hacker gets access to your database or somehow gets a user’s password to print out on the screen then it’s over.
Bad: Encrypting Passwords
The next way a developer might think about storing passwords is by encrypting them. The developer takes the user’s new password encrypts it and saves that to the database. When the user goes to login again, you simply take the encrypted password out decrypt it, compare it and success.
The issue: This is still reversible, and the hacker can still decrypt the passwords to what the user entered if the database is hacked. The user, hacker, and even you as the developer should never be able to see the password after it is saved.
Bad: Basic Hashing (MD5, SHA1, etc)
After this, people started to use one-way hashing. MD5() was the famous way of doing this. You will still find tutorials around the wasteland of the internet. (If you find one put a link to this post in the comments for those that might run across it.) The developer would take the password md5 it into a 32 character hash and save it. When the user went to sign in, the developer would take the entered password, md5 it, then compare the two hashes. If it matched, it was right, and the user was let in.
The Issue: Hackers started to md5 everything and anything. They would take plain text passwords and store them in the database with the hashed values. This method is called a Rainbow Table. You can search for “MD5 Decrypt” on Google and find massive databases of these converted hashes. This makes it easy to figure out what a hash might be.
Bad: Salted Password
Next up came the salted passwords. The developer would take the users password, generate a random md5 hash that was the salt, and then md5 the user’s password with the salt. The salt was saved in the database in plain text, or possibly encrypted. When the user would sign in, the developer would take the user’s password and stored salt and md5 them the same way. After that, you simply compare the hashes.
The Issue: Compute power is cheap and easy to get. This means that you can build a custom rainbow table on each stored password. Using video cards hackers were able to get 348 billion hashes per second.
Good: 5.5+ Password Hashing
PHP 5.5 has introduced a new method of password hashing. We will cover it here so that you understand it and can share it with others. This method has three functions for us to review.
string password_hash ( string $password , integer $algo [, array $options ] )
The password_hash() function is used to hash the user’s password. It will return a string that you can store in the password column of your database. The string size can be mixed lengths over time and it is recommended to store this string in a 255 varchar column.
So it hashes a password, what is so special?
The trick is that the string holds four pieces of information. The Algorithm, Cost, Salt, and Hash. Let us look over the jobs of each.
The default algorithm is bcrypt. However, this can change over time. It’s recommended that you keep the algorithm set to PASSWORD_DEFAULT. PHP will update this as the PHP version increases. However, if you used a 255 varchar column, you won’t need to worry. Also, since the algorithm is stored in the string different users can have different algorithms.
The cost is unique here. You will need to test the cost on your own server, and try to get the timing between 50ms and 100ms. The idea is to make the server work harder while hashing the password. Even if hackers have powerful computers they will need to use extra resources to generate a rainbow table on each password. This can majorly reduce the speed of hackers.
The salt is the same as the adobe methods. In PHP 5.5 you can set your own salt, however, in PHP 7.0 this has been removed as developers tend to make bad random salts.
The hash is the same idea. It will be different because it uses the algorithm chosen, but is still a one-way hash.
boolean password_verify ( string $password , string $hash )
The password_verify() function will return back true or false. This will break the password_hash() string up and use the parts to match the password. That is pretty much it.
boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )
The password_needs_rehash() function is pretty cool. After the user’s password has been verified and the developer still has access to the plain password the user entered, you can check to make sure it is using the latest password_hash() methods. If not, you can rehash their password and update your database without having to ever promted the user. However, this also means that older accounts that don’t login often will continue to use the older methods until you get them to update their password or sign in.
These great new methods should help to keep the user’s passwords more secure and protected. Now to scrub the world of md5 password hashing tutorials!