Working With Passwords In PHP 8
In our previous article, we discussed how we should hash and salt our user’s passwords to make them harder to crack if our database becomes compromised. In this article, we’re going to discuss how to use PHP’s built-in functions to do this.
As someone who has maintained this kind of logic in other systems, I’m so glad it was added to the core.
Before we get too far into this, these functions were added in PHP 5.5 so our examples won’t work with earlier versions. These versions are no longer supported so they should be upgraded ASAP!
password_hash()
The first function we’re going to discuss is the password_hash()
function. This function takes just the password and a constant indicating the algorithm to use and returns a hash. We’re going to use the PASSWORD_DEFAULT
constant.
The string we get back from this is almost gibberish which is a good indication we’re getting a good hash.
$2y$10$nqtoiMsWow3PKz8Fry7RIu/Cac.bg3sAEsRt9aL2qPXnbc4sDVqOW
Because the password_hash()
function automatically salts our passwords, every time we run the same password through the function we’ll get different outputs. This means the function won’t be susceptible to a rainbow table exploit.
Output:
$2y$10$7lmWDeZjkddfWax4oZDCo.1ljtnPz0F2FN59d0HTTM4UzngY2JYD2
$2y$10$AGhT74u7uQIfW0u8R7QMee1irjRXCLgDLunJwYm9Cf1EcJNQZlUfq
$2y$10$YPNbZ1zPVwAzG43Lo8jR6OcBbAWYTbzsgHf3uMq00w8HomRcyu42K
We can also specify the algorithm to be used to generate the hash and some options for the specified algorithm.
The algorithm choices are PASSWORD_DEFAULT, PASSWORD_BCRYPT, PASSWORD_ARGON2I, and PASSWORD_ARGON2ID for bcrypt, bcrypt, Argon2i, and Argon2id respectively. You may have noticed we said “bcrypt” twice and that’s because PASSWORD_DEFAULT is equivalent to PASSWORD_BCRYPT.
Our suggestion is to stick with PASSWORD_DEFAULT as people with more security knowledge than us have decided that it is the best option for most people and if that changes in future releases we’ll most likely upgrade to the new algorithm automatically.
The options array parameter for bcrypt is the algorithmic cost that should be used. The higher the number the longer it will take to generate the hash and the harder it will be for an attacker to brute force the password.
The default cost is 10 but it’s hard to understand how that affects anything so let’s run through how long it takes to generate a hash at each level. Please note these numbers will not match on any other computer so take them with a grain of salt and use your server to determine the best value for you. We recommend something around a tenth of a second as a good compromise between security and performance.
The output:
0.001 for cost = 4
0.002 for cost = 5
0.005 for cost = 6
0.011 for cost = 7
0.021 for cost = 8
0.042 for cost = 9
0.098 for cost = 10
0.161 for cost = 11
0.502 for cost = 12
0.687 for cost = 13
1.495 for cost = 14
2.684 for cost = 15
3.796 for cost = 16
7.737 for cost = 17
password_verify()
The next part of the password management cycle is to verify the password an unauthenticated user has passed us. This is done using the password_verify()
function.
Notice how the hashes we’ve generated start with $2y$10$
? That is how password_verify()
knows how to compare the hash to the input. This makes it so the password_verify()
function needs just two parameters, the password sent by the user and the hash we created using password_hash()
. I love this because even if we change our algorithm or cost the function call doesn’t need to change.
password_needs_rehash()
Computing power is only getting more and more powerful so as our servers get faster we must rehash our user’s passwords as we increase our “cost” parameter. PHP provides the password_needs_rehash()
function to determine if we need to rehash our user’s passwords based on the current settings. It has almost the same parameters as password_hash()
but the first parameter is the hash and not the password.
As a form of completionism, a sample login process looks something like the following.
password_get_info()
The very last thing we want to discuss is the password_get_info()
function. This function is used to extract the information from the hash. It’s mostly for fun but we wanted to make sure you were aware of it.
array:3 [
"algo" => "2y"
"algoName" => "bcrypt"
"options" => array:1 [
"cost" => 10
]
]
What You Need To Know to Nail a Job Interview
- PHP has built-in password functions after the 5.5 release
password_hash()
to generate the hash before storing itpassword_verify()
to compare the hash against a user-provided passwordpassword_needs_rehash()
to determine if we need to rehash the passwordpassword_get_info()
for debugging information
As always thanks for reading our article. Make sure you subscribe to our newsletter and let us know how you’re using PHP password functions in the comments.
Scott Keck-Warren
Scott is the Director of Technology at WeCare Connect where he strives to provide solutions for his customers needs. He's the father of two and can be found most weekends working on projects around the house with his loving partner.
Top Posts
- Working With Soft Deletes in Laravel (By Example)
- Fixing CMake was unable to find a build program corresponding to "Unix Makefiles"
- Upgrading to Laravel 8.x
- Get The Count of the Number of Users in an AD Group
- Multiple Vagrant VMs in One Vagrantfile
- Fixing the "this is larger than GitHub's recommended maximum file size of 50.00 MB" error
- Changing the Directory Vagrant Stores the VMs In
- Accepting Android SDK Licenses From The OSX Command Line
- Fixing the 'Target class [config] does not exist' Error
- Using Rectangle to Manage MacOS Windows