The idea behind securely storing passwords in the database is to prevent them from being cracked. If data leakage wasn't a problem, just saving them in plain text would be enough. But we don't need to explain the importance of protecting ourselves against cybercrime here, right?
Before talking about storing passwords, let's explore some ways to crack passwords already in hash form.
Disclaimer: The purpose of this article is completely didactic and for you to use it for security only. Cyber attacks are a criminal activity and we've very serious about its implications. Now, back to our article.
As a user, you also need to build “unbreakable” passwords and if possible a different password for each site you register. Password managers like 1password are great for this purpose.
The first thing we can do with a hash list in hand is to group the same hashes and order the ones that appear the most. In real life, if you find two, three or more hashes that are the same, it means it is probably some common password and they don't use any custom information like "123admin". Even without a password cracking program, we can already get this hash and google it. If it's a regular password, you'll probably already find the plaintext form.
Tools like Hashcat allow you to use different techniques and over 200+ different hashing algorithms, using both CPU and GPU. This gif below was taken from a short video someone made in which they crack several passwords on a random website. They are using a Core i5 notebook with a bad GPU and look at the speed at which it can crack passwords by doing a brute force with 6 letters + 2 numbers. As per the status of the hashcat itself, the retrieval speed was an unbelievable 101.4 million hashes per second.
Terrifying, isn't it? So, what can we do?
Securely storing passwords in the database.
Before talking about the database itself, there are two important things about registration forms. First, never limit the types of characters (special characters, for example) that a user can choose for a password. Many sites do this out of fear of an SQL Injection. The problem is that you protect yourself while you make your users' passwords weak, making them vulnerable. Instead of making a workaround to protect themselves, websites should correct their codes, so that it does not suffer any injection attacks.
The most important attribute of an algorithm is the use of the salt technique.
For those who don't know, salt is a random, unique value with a fixed size. You can find out more about it here. And when I say unique, I mean universally unique, not just to the system or database. The salt must be concatenated with the user's password and sent to a hash function. With this result in "hands" you will save in your database the salt generated for this password and the hashified result. In practice, a pseudo-code would look something like:
result = salt + func_hash([salt] + [password])
*9o4$.$a&2*a = *9o4$ + hashify(*9o4$ + 123456)
That is, if another user creates the same password, the fact that you always generate a new salt will make the result completely different.Also, as you saw, the salt is visible along with the hash. That is, do not confuse the salt with the encryption key, which is a value that must be hidden. It's a different thing.
Prevent collision attacks, that is, the attacker will not be able to group and order the same hashes by the ones that appear the most, because no hash will be the same (even if users have the same passwords) and consequently it will be expensive to carry out a dictionary attack;
Increase the level of password protection without relying on the user to create a complex password (which does not exclude the need for the user to choose a good password).
An algorithm that is very fast generating hashes might sound good, after all your application will get even faster, right? But those who really like this are also the password cracking tools.
A good algorithm preferably has a reasonably high cost of RAM. Just as we don't want fast algorithms, we also want the person to have high memory resources to carry out the attack, or their attempt to crack the password will take hundreds of years. You won't develop any of this alone. Mathematicians, cryptographers and security experts have already tested and analysed tons of effective algorithms, so please do not try to develop your own hash algorithm. Use ready-made functions with salt technique and a good processing speed to block attackers in your application.
Argon2 is the winner of the Password Hashing Competition, an open competition from 2013 to 2015 organised by several security experts from around the world from several universities and world-renowned security organisations. To this day, it is still the most recommended hashing algorithm.
It allows you to configure the cost of RAM memory to generate the hash, the time cost that is given in number of iterations, the size of the hash generated at the end and the number of threads it must create to generate the hash.
If for some reason you cannot use Argon2 (if a security certification such as FIPS is required or another corporate requirement, for example), you should choose the PBKDF2 algorithm. It was created by RSA Security in 2000, that company that created the famous RSA encryption algorithm. In 2017 it was still the most recommended algorithm by the IETF in RFC 8018, despite receiving a lot of criticism because of its low cost of RAM memory (something you don't have to worry about with Argon2 or Scrypt). Still, it allows you to configure the number of iterations needed to generate the hash and the size of the final key.
If you can't use Argon2 and also don't need any certification or specific support, Scrypt is a safe bet. It was published in 2016 and the big difference from scrypt to PBKDF2 is that it was created to protect against parallelism, requiring a large amount of memory for processing, something PBKDF2 does not care about. It allows you to configure the amount of RAM and the size of the final key.
Now, if you can't use any of these 3 alternatives, choose Bcrypt. It was published in 2014 and is the standard used by OpenBSD to test file integrity and some Linux distributions.
Although it doesn't allow you to create the salt, you can configure the number of iterations when creating the hash.
Added security with encryption
You can also choose to use an algorithm with an authentication code. Although this technique is used to encrypt data that would later be decrypted to be read by a human, it can also be used to encrypt a hash. In this case, you need to have a key somewhere that is not available to anyone who, hypothetically, could have access to your database or your application code in a hacking attack.
This key would be used to decrypt the hashes saved in your bank and only then you would verify the password. That is, even in the case of a data breach, there is no way to run a password cracking program without the key.
HMAC is another algorithm you can combine with PBKDF2 (native support). Many languages already have libraries that do all this for you with just one function, so you don't have to manually take care of encryption and hashing separately.
These are our suggestions to securely store passwords in the database without exposing yourself, and your data. By not taking them, you're being negligent by putting your users' passwords at great risk, and might lose the race against cybercriminals.
At Vaultree we are building an encrypted future. We love sharing valuable information and trends to help you keep your data safe. Sign up to stay in the loop and discuss the hottest trends in cybersec with a team of experts.