Using strong hashes to store passwords
What is an insecure hash?
Well, what is a hash? Hashing refers to taking some input value, usually a password, and then producing a fixed length "fingerprint" from it. Unlike encryption where the original message can be retrieved, there is no (algorithmic) way of reversing a hash back to its original value.
An insecure hash vulnerability is a failure related to cryptography. Cryptography being the way we encrypt or hash data. By having an insecure hash there is a high chance that your data will be exposed. Something we don’t want as a business or as a customer!
As computing power is steadily increasing, hashes might get weak to brute force attacks. Let’s face it, computers are fast and there is a real possibility of an attacker using a tool to try different passwords until the right one opens up the vault to all our secrets! Hashes can also be insecure due to rainbow tables or hash collisions.
We should be aware of what hash algorithms are good to use and which ones are no longer perceived as secure. Insecure hash isn’t an attack but is a symptom of a larger attack. Many legacy systems still use MD5 as a hash function to store passwords. In this lesson, we’ll see why that is a bad practice.
About this lesson
During this lesson, we will learn what an insecure hash is and why exactly it is considered insecure. We’ll look at how an attacker can use a hash lookup table against our hashes to discover sensitive data. After that, we’ll learn how to create a secure hash and fix our vulnerability.
MD5 hash algorithm
The MD5 hash algorithm was developed in 1991 and released in 1992. Only a year later, researchers were already finding flaws! However, it continued to be used and adopted by developers around the world. In 2005, it was officially deemed unsuitable, yet, in 2019, it was estimated that 25% of content management systems still use MD5!
Congratulations on the new job! You are working at Saturn Bank as a developer. In your first week, you are reviewing some of the code and you notice that during registration, the hash function is using MD5 to hash the user's password before it gets stored in the database.
You know MD5 is insecure and you bring this up to your boss. Your boss, who used to be in your role, thinks it’s not a big deal because a hash can’t be reversed. He claims there is no way an attacker can figure out someone's password by looking at the hash. He’s so confident that he gives you the hash of his password! The hash is
But a hash can be compared to known hashes. This might take a lot of effort to brute force some hashes, but maybe you just need to look at the most popular passwords and hash those.
In this tutorial, we’re going to pretend to be an attacker who just received a hash of someone's password. We are then going to try and discover what this password really is!
Insecure hash discovery
- STEP 1
- STEP 2
- STEP 3
- STEP 4
- STEP 5
Setting the stage
Your boss claims there is no way an attacker can figure out someone's password by looking at the hash. But you have his, so let's see what we can do!
An MD5 hash can be brute forced in a matter of seconds. Normally, your boss won’t hand over his hash but an attacker can access these if they break into a database (that’s a different, scary problem).
Hashing passwords is the correct way to handle passwords, but it must be done using a secure hash function. Outdated hash functions such as MD5, SHA-1 or some others, should be avoided.
With Python, there is a library called
hashlib that allows you to use Python’s implementation of Password-Based Key Derivative Function 2(PBKDF2).
MD5 isn't all bad
While the usage of MD5 in security and cryptography is depreciated, it can still be used as a hash algorithm in hash map data structures for example. So, just because you see MD5 being used, doesn’t necessarily mean it is an insecure implementation. It depends on the usage.
How do you mitigate an insecure hash?
There are multiple steps that need to be taken to mitigate this vulnerability. First, we need to use a stronger hash function. MD5 is not secure and it hasn’t been recommended for years! But as you can see, a secure hash might not be enough. If your company decides to use a really strong hash function but a user still uses a weak password (such as Password1), the hash may still be found in a hash lookup table.
We need to use the strong hash function but we also need to implement strong password policies. On top of that, we can salt a hash to make it even more secure.
A salt is a random string that gets attached to a plaintext password before it gets hashed. As we saw above, a hash cannot be reversed but it can be compared with existing generated hash outputs. If a user is using a weak password, that password may have been hashed and stored somewhere for potential hackers to compare against. By adding a salt to the password, the hash output is no longer predictable. This is because it is increasing the uniqueness of the password, thus, the uniqueness of the hash itself.
By adding a salt to the password, you can see how the output changes.
What is randomness?
Randomness is a topic that spans many areas including computer science, mathematics, and philosophy. The question of “what is randomness?” still looms today. But the concept of randomness is incredibly important to cryptography. If, for example, a salt could be guessed or predicted, that would lead to the creation of an insecure hash. Depending on what language you are developing in, you need to be careful about which random function you are using (https://www.php.net/manual/en/function.rand.php).
hashlib library allows you to hash your passwords securely and apply a salt. Keep in mind, when you generate the salt, you need to keep this stored as well. Typically, this is stored in the database with the generated hash.
Test your knowledge!
In Python, which of the following methods is recommended for generating a cryptographically secure salt?
- Storing passwords is crucial to any application. Learn more about the best practices here
- Here are some other great tips on how to deal with passwords
- NIST provides these guidelines for US federal use of hash functions
- bcrypt is available across many languages, but here is some additional information on it for NodeJS
- Of course, XKCD has a comic about passwords!
You have taken your first step into learning what an insecure hash is, how it works, what the impacts are, and how to protect your own applications. We hope that you will apply this knowledge to make your applications safer. We'd really appreciate it if you could take a minute to rate how valuable this lesson was for you and provide feedback to help us improve! Also, make sure to check out our lessons on other common vulnerabilities.