7

Given a database where we have usernames and passwords, we want to secure users' passwords by hashing them. We should not use only username and passwords in this hash, as someone having data from other sites that uses the same hashing function can come to the same results and thus know our passwords. If we try hashing the passwords by themselves it would be easy to bruteforce the entire database and guess all the passwords. In normal applications, passwords are hashed with a random salt that is stored along with them to prevent them from being bruteforced easily.

However, we could just use username, password and the same salt for every record in the database. This option would save one data field for each record, while the combination of username and password would be unique for our entire database. Is such a solution just as safe as the traditional password hashing scheme, or are there some security drawbacks to them I am not aware of?

ThePiachu
  • 1,689
  • 2
  • 18
  • 26

1 Answers1

8

Let's try to avoid random per-password salts. If the only requirement for salt is to be unique, which is the case for good password hashing schemes, you'll need:

  • $globalSalt$ is a secret random 32-byte string.
  • $userId_n$ is a unique user identifier.

You can use, for example, $HMAC$-$SHA256(globalSalt, userId_i)$ to generate salt for each user $i$. Or, with PBKDF2 or scrypt, you can just concatenate the values of $globalSalt$ and $userId_i$.

This scheme achieves uniqueness for salt only when you don't allow users to change their passwords. If you do, salt will be unique per user, not per password, so if someone changes their password, their salt will stay the same. In which case, if there are database leaks at, say, three points in time, given that the salt is unique per user, not per password, the attacker gets some information about passwords (e.g. if the user changed their password to the same value.)

To make salt unique per password, you also have to include some counter of password changes, which you have to update and store, and concatenate with $userId$. Storing this counter per-user defeats the original intention, so you can have a single global counter, making sure it never repeats, in which case you can also drop $userId$ and just use this counter along with $globalSalt$.

If $globalSalt$ is leaked, the only advantage the attacker gets is that he will be able to precompute future hashes for current and future $userId$s, which doesn't seem very useful.

We avoided generating and storing random salts by building a more complex and less secure system. Thus, it's much simpler and more secure, as others said, to use random salts instead of bothering with implementing your own scheme.

dchest
  • 1,192
  • 1
  • 14
  • 22