I think there is a contradiction about the recommendations how to store password in database. We hash the password and store it in DB, and when a user tries login, we hash his input string the same way and compare to the DB. that's fine. But there are recommendations to strengthen that hash by adding a random salt. here is the problem: So we lose the whole point of comparison, because the salt values will be different between the first hash to store in DB and the salt when login?? If to store in Db the salt, so what is the benefit is salting at all?
-
Also see OWASP's Secure Password Storage. John Stevens did a really nice job of creating the threat models and placing security controls to contain the threats. It includes the reason for salting a password.jww– jww2017-07-06 01:27:06 +00:00Commented Jul 6, 2017 at 1:27
-
"If to store in Db the salt, so what is the benefit is salting at all?" - Salting ensures two users who happen to select the same password don't collide in the database. Without it, a user could use his password to probe for other user's passwords (assuming he/she had a way to dump the user table). Upon a hit, he/she could spoof as a different user because he learned the password.jww– jww2017-07-06 01:29:40 +00:00Commented Jul 6, 2017 at 1:29
-
@jww - Getting different hashes for equal passwords is only a minor benefit of salting, the actual reason is to prevent rainbowtable attacks.martinstoeckli– martinstoeckli2017-07-06 07:43:26 +00:00Commented Jul 6, 2017 at 7:43
-
@martinstoeckli - A single salt for the entire table will provide the protection against precomputation. See ATTACK 1.2 in the threat model detailed at Secure Password Storage.jww– jww2017-07-06 08:02:53 +00:00Commented Jul 6, 2017 at 8:02
-
@jww - That's true and it is not related to collisions. Precomputation means that you cannot calculate the rainbowtable before you know the global salt, but you can build 1 rainbowtable to get all passwords. Unique salts negate the advantage of rainbowtables at all. I wrote a small tutorial about safely storing passwords, maybe you are interested.martinstoeckli– martinstoeckli2017-07-06 11:28:04 +00:00Commented Jul 6, 2017 at 11:28
2 Answers
You also store the salt. Comparison is between stored hash value and HASH(salt + input). The purpose of the salt is to prevent two users that use the same password to generate the same hash.
3 Comments
The reason why we generate a random salt for each password is, that one cannot build a single rainbowtable to get all passwords at once. Instead an attacker has to build a rainbowtable for each salt/password. Building a rainbowtable to get a single password is pointless, because you can stop searching if you found a match.
In other words, salting prevents the usage of rainbowtables. This purpose is fulfilled even if the salt is known, one still has to build a rainbowtable per password, that's why we can store the salt together with the hash in the database.
Btw: The SHA-* hash functions are not appropriate to hash passwords, instead one should use a password-hash function like BCrypt, SCrypt, PBKDF2 or Argon2. They all have a cost factor to make hashing slow.
Edit
Following examples are only for better understanding, the salt should not be added this way:
1. Example with the same (global) salt for all passwords:
hash("Password1"+"o9*eiwrC49YAS2395%tu") => hash1
hash("Password2"+"o9*eiwrC49YAS2395%tu") => hash2
hash("Password3"+"o9*eiwrC49YAS2395%tu") => hash3
To find out Password1, we can build 1 lookup table with all reasonable passwords and the global salt. To find out Password2 we can reuse the same lookup table, because all passwords use the same global salt.
2. Example with unique salts for each password:
hash("Password4"+"ierukElasidj42Swiekq") => hash4
hash("Password5"+"oeuoElwWPJckfk212344") => hash5
hash("Password6"+"PoiMnmdvhas98akd73lk") => hash6
To find out Password4 we would have to build 1 lookup table with all reasonable passwords and the salt "ierukElasidj42Swiekq". To find out the Password5 one has to build another lookup table with the salt "oeuoElwWPJckfk212344" and so on. The first example required 1 lookup table, the second example requires as many lookup tables as passwords.