It’s important to know how to hash a password in any programming language, and in this quick tip article we’ll explain how to do that in PHP, and why hashing passwords is so important.
Every PHP programmer at some point will need to write an application that relies on user login to properly function. Usernames and passwords are normally stored in a database and then used for authentication. As we know, passwords should never be stored in plain text in the database: if the database is compromised, all of the passwords will be open for use by malicious actors. That’s why we need to learn how to hash a password.
Notice how we’re using the word hash rather than encrypt? This is because hashing and encryption are very different processes that are often confused.
Hashing
A hashing function takes a string like mypassword123
and converts it to an encrypted version of the string, known as a hash. For example, mypassword123
might be hashed to produce a seemingly random string of numbers and letters such as 9c87baa223f464954940f859bcf2e233
. Hashing is a one-way function. Once you hash something, you get a fixed-length string — a process that can’t be easily reversed.
We can compare two hashes to check if they both came from the same original string. Later in this article, we’ll have a look at how we can implement this process using PHP.
Encryption
Similar to hashing, encryption will take an input string and convert it into a seemingly random string of numbers and letters. However, encryption is a reversible process — if you know the encryption key. Because it’s a reversible process, it’s a poor choice for passwords, but excellent for things like peer-to-peer secure messaging.
If we encrypt a password instead of hashing it and the database we’re using is somehow accessed by a malicious third party, all user accounts will be compromised — which obviously isn’t a good scenario.
Salting
Passwords should also be salted before being hashed. Salting is the action of adding a random string to a password before hashing it.
By salting passwords, we can prevent dictionary attacks (where the attacker systematically enters every word in the dictionary as a password) and rainbow table attacks (where the attacker uses a list of hashes of common passwords).
On top of salting, we should use a somewhat secure algorithm when hashing. This means it should be an algorithm that hasn’t already been broken, and preferably one that’s specialized rather than a general-purpose one (like SHA512).
As of 2023, the recommended hashing algorithms are:
- Argon2
- Scrypt
- bcrypt
- PBKDF2
Hashing with PHP
Hashing on PHP has been made easy since PHP5.5 with the introduction of the password_hash()
function.
At the moment, it uses bcrypt (by default) and has support for other hashing algorithms like Argon2. The password_hash()
function also takes care of salting the password for us.
In the end, it returns the hashed password. The cost and salt are returned as a part of the hash.
In simple terms, the cost in a password hash refers to the amount of computation that’s required to generate the hash. It’s like a measure of how “difficult” it is to create the hash. The higher the cost, the more difficult it is.
Imagine that you want to make a cake, and the recipe for that cake says “beat the eggs for five minutes”. That’s the “cost” of making that cake. If you want to make the cake more “secure”, you might change the recipe to say “beat the eggs for ten minutes”. Now it takes longer to make the cake, and that’s like increasing the “cost” of making the cake.
As we can read on the password_hash()
documentation:
… all information that’s needed to verify the hash is included in it. This allows [
password_verify()
] function to verify the hash without needing separate storage for salt or algorithm information.
This ensures that we don’t have to store additional information on our database to verify the hash back.
In practice, it looks like this:
<?php
$password = "sitepoint";
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($password, $hashed_password)) {
//if the password entered matches the hashed password, we're in
} else {
// redirect to the homepage
}
More information on the password_hash()
function can be found here, while password_verify()
can be found here.
Conclusion
It’s important for PHP programmers to understand the difference between hashing and encryption, and to use hashing for storing passwords to protect user accounts from compromise. The introduction of the password_hash()
function in PHP 5.5 made it easy for programmers to securely hash passwords using a variety of algorithms, including Argon2 and bcrypt.
As described by Tom Butler in PHP & MySQL: Novice to Ninja:
Luckily for us, PHP includes a very secure way of hashing passwords. It’s created by people who know a lot more about this stuff than you or I, and it avoids developers like us needing to fully understand the security problems that can occur. For this reason, it’s strongly recommended that we use the inbuilt PHP algorithm for hashing passwords rather than create our own.
Make sure you consider that and to stay up-to-date on the latest recommended hashing algorithms to ensure the best possible security for your applications.