If you’ve been paying attention in the past few years, you may have seen that password breaches have made headlines more than a few times. In many of these cases, each breach's overall impact on users depended on whether or not they hashed passwords and how well they did it. One security measure is password hashing, but what exactly does “hashing” mean? This post will explain password hashing, why it’s crucial, and various ways it is achieved.
Hashing Versus Encrypting
In layman's terms, these two security measures might seem identical because they are both methods used to protect sensitive data. However, in nearly every single situation involving passwords, they should be hashed rather than encrypted.
Encrypting a password, plainly put, means scrambling a password up through several steps. A key point here is that encryption is a two-way function so that an encrypted password can be decrypted back to their original form.
Hashing is a one-way function, meaning once a password has been hashed, it can’t be restored to the original inputted plain text. However, that doesn’t mean that hashing solves all your problems. In the next section we’ll see how an attacker can still recover the original password - and additional techniques we need to use to make it near impossible for them.
Cracking a Hash - a.k.a. what if we just guess a lot?
While it’s true you can’t truly “decrypt” a hashed password, there are methods for “cracking” the hashes themselves. If an attacker can gain access to a database and has a list of hashed user passwords, it is possible they can still figure out the plain text passwords.
The process breaks down into a few steps:
First, an attacker guesses a password they think a user might have chosen. Let’s say the attacker thinks the user picked very poorly and chose to use “password” as their password.
Second, the attacker calculates the hash for their guess.
Finally, they compare their calculated hash for their guess with the actual hash they gained from the database. If they match, the attacker correctly “cracked” the hashed password.
Now, while that process would take an enormous amount of time when using it for a large amount of passwords, there are ways attackers can cut down on the number of guesses they need to make. For example, they could take a list of passwords from another compromised site (this is called a credential stuffing attack). They could use high-speed hardware to run through these permutations incredibly fast. They could also just check passwords of up to seven characters, allowing them to target weaker, easier-to-crack passwords rather than stronger ones (this is called a brute force attack).
Best Practices and Options for Hashing
Adding a little seasoning is one way to add security to your password hashing. You could add “salt” to each user’s hashed password, which is random data added to each one. Each user gets their own salt, so there isn’t a universal salt for an attacker to use to figure out hashes. This makes it so that you can only crack one person’s password at a time.
However, the salt itself is usually stored alongside the password hash, so an attack that goes through a list of commonly used passphrases will still work if you choose a bad password. Hashing algorithms typically used for password hashing (bcrypt, scrypt, Argon2) will salt your data for you. Regular hashing algorithms, like sha256, won’t.
Slowing Down Checks
Another method for adding complexity is increasing the time it takes to check one hash, also known as the work factor. A higher work factor means a higher computational cost for an attacker to crack the hash. However, this comes with a performance hit to your product, so there is a tradeoff.
Bcrypt, as one example, lets you configure the work factor. Argon2id lets you control the work factor and the amount of memory required - giving you both time and memory constraints for the hash.
Preventing easy to guess passwords
Probably the most common method you’ll see is password complexity requirements. A simple length check can go along way to preventing the really egregiously bad passwords. You can also prevent your users from using common passwords by using a dictionary or a service like haveibeenpwned.
The idea here for all of these practices, though, is that attacks on password hashing often involve, “Let’s guess at solutions as much as possible,” so mitigating these attacks boils down to either making each guess more expensive or making obvious guesses hard to use by requiring more complicated passwords from your users.
There’s so much more to password hashing, from various hashing algorithms to adding “pepper” to a password. Hopefully, this has been a helpful overview of the concept, and we’d suggest looking at OWASP’s guide for even more information.