DEV Community

loading...
Cover image for How to properly store a password in the Database

How to properly store a password in the Database

pazvanti profile image pazvanti Originally published at petrepopescu.tech ・4 min read

Article originally posted on my website un How to securely store the password in the Database

When I started LOGaritmical, one of the first functionalities that I implemented was registering a new user. This meant that I had to store the user’s password in the database in a secure way and I will need to be able to verify that the password entered during login is correct. This is something that is quite easy to implement incorrectly and you would be surprised (or not) at how many systems and websites store passwords in an incorrect way.

Just look at the number of data leaks from the past few years. It is very likely that your password was leaked at least once, and from a well known and high-profile source. Also, did you ever register for a website, entered the username and password you wanted, and after registration you got an email with the password in clear text? Chances are that the storing was also as insecure.

So, before I show you how to properly store a password (and what mechanism I used for LOGaritmical), let me tell you straight away how NOT to do it:

  • Clear text – NEVER STORE PASSWORDS IN CLEAR – I can’t believe I have to say this. Passwords should not be stored in clear text because any DB dump can easily extract the email and password combination and try it out on other websites.
  • Use your own algorithm – Unless you are a genius in mathematics and encryption, don’t write your own algorithms for encrypting or hashing the password. It may not be as secure as you think.
  • Simple hash – Even though not as bad as the first two, it is not very far away. There are rainbow-tables attacks that can be done on the DB dump and most of the passwords can be easily recovered. A rainbow table is a pre-computed file that has the known hash for many passwords. The file can store hundreds of thousands of passwords and their hash with different algorithms. Next, it is just a matter of matching the DB hashes to the pre-calculated file. Not all passwords will be recovered, but most of them will.

How to securely store the password in the database

The best way to store a password in a database is by using a salted hash algorithm. This way, even in case of a DB dump leak, it will be almost impossible to recover the passwords. How does adding a salt help? First, let’s explain what the salt is. The hash salt is a randomly selected string (or bytes) that is added to the password before hashing it. It does not really matter if you append it or prepend it, as long as you are consistent and the salt is strong enough.

In the database you store the salt for each user and the obtained hash for the salt+password. Keep in mind (and this is very important) each user must have his own salt and it must be changed whenever the password is changed. Also, in order to be sure that the salt is strong enough, it is recommended to be at least 64 bytes long.

Next, use a strong and widely used hashing algorithm. In the past MD5 was considered good enough, after that SHA-1 was recommended, but nowadays it is SHA-256 or better are considered necessary. There are other algorithms as well, but please read about their strengths before deciding to use one.

Hashing algorithms usually have a number of iterations. Here we must be consistent since it will affect the output even if the salt and passwords are the same. Keep in mind though that the greater the number of iterations, the longer it will take for the hash to be computed. This is great since it minimizes the possibility someone will do a brute-force attack in case a DB dump gets leaked. Do some testing to see what is a good number of iterations for your system, without putting any major load on it.

How to check the password entered is correct?

We have the password stored the right way. We have a salt that is unique for each user and a secure hashing algorithm was used. But hashes are one-way functions, which means we can no longer retrieve the password from a given hash, so how do we check during login that the password the user-submitted is the correct one?

We simply compute the hash again for the user-entered password. We retrieve the salt from the DB, we attach it to the user’s password, and recompute the hash using the same algorithm that was used when saving the user’s information. After that, we compare the resulted hash with the one stored in the database. If they are identical, the password entered is the correct one.

How I stored passwords in LOGaritmical

Now that we have all the details, let’s look on how I stored the password in LOGaritmical and how to write a similar functionality in Java. I created a utility class that handles this part. It can generate a salt and it can compute the hash of a String with a provided salt. I chose the following values for the hash strength:

  • Salt length – 521 bytes
  • Hash byte size – 256
  • Iteration – 1000
  • Algorithm – PBKDF2WithHmacSHA512
  • Always used SecureRandom

Below is a part of the utility class (as it is currently is in the project). For the full and updated version feel free to look over the code in LOGaritmical repo.

/**
 * Generates a cryptographically secure 512 bytes string that can be used as a password salt
 */
public static String generateSalt() {
    byte[] bytes = new byte[512];
    secureRandom.nextBytes(bytes);
    return Base64.getEncoder().encodeToString(bytes);
}

/**
 * Generate a hash for a password
 */
public static String generateHashForPassword(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
    byte[] hash = secretKeyFactory.generateSecret(spec).getEncoded();
    return Base64.getEncoder().encodeToString(hash);
}
Enter fullscreen mode Exit fullscreen mode

Discussion (2)

pic
Editor guide
Collapse
kalkwst profile image
Kostas Kalafatis

Nice write up!

You could also use a "pepper" in addition to the salt, in order to add an additional layer of protection.

The purpose of the pepper is to prevent an attacker from being able to crack any of the hashes if they only have access to the hash database.

You can hash your password as usual, and then encrypt the hashes using a symmetric key algorithm with the pepper playing the role of the encryption key, without affecting or interacting with the hash or the password itself in any way.

This will provide an additional layer of protection if the password database gets dumped, but also keep the passwords valid if the pepper is considered compromised.

Note that the pepper should not be stored in the database!

Collapse
pazvanti profile image
pazvanti Author

Indeed, using a pepper is also a good idea. This does add a bit of extra work, so it may depend on the actual use-case of the app if it is worth it. Then again, hardware is quite cheap nowadays. Thanks for pointing it out.