Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I need a "random salt" once per password or only once per database?

Further to my previous question about salted passwords in PHP/MySQL, I have another question regarding salts.

When someone says "use a random salt" to pre/append to a password, does this mean:

  • Creating a static a 1 time randomly generated string of characters, or
  • Creating a string of characters that changes at random every time a password is created?

If the salt is random for every user and stored along with the hashed password, how is the original salt ever retrieved back for verification?

like image 276
barfoon Avatar asked Jun 08 '10 16:06

barfoon


People also ask

How many times should you salt a password?

Salts should be 32 characters or longer in length. Avoid using outdated hashing algorithms, such as MD5 and SHA1. Ensure you hash the salted passwords multiple times. For the average website, you'll want to recursively hash 1000's of times.

Should a salt be unique for each password?

A system-wide salt also easily allows an attacker to keep using hash tables. We should hash and salt each password created for a user. That is, we should generate a unique salt upon creation of each stored credential (not just per user or system-wide).

Should each user have a different salt?

A new salt should be randomly generated for each user and each time they change their password as a minimum. Don't just rely on a site wide salt for example, as that defeats the point of using a salt in the first place.

Does each password have its individual salt or do all passwords share the same salt?

A new salt is randomly generated for each password. Typically, the salt and the password (or its version after key stretching) are concatenated and fed to a cryptographic hash function, and the output hash value (but not the original password) is stored with the salt in a database.


3 Answers

A new salt should be randomly generated for each user and each time they change their password as a minimum. Don't just rely on a site wide salt for example, as that defeats the point of using a salt in the first place.

Using a unique salt for each user is so that if two users have the same password they won't get the same resultant hash. It also means a brute force attack would need to be mounted against each user individually rather then being able to pre-compute a rainbow table for the site.

You then store the result of hashing the salt and password in the database hash(salt + password), along with the salt for each user. You can store these in separate columns, or all in one column (separated by some character not used in the hashes, so ; for example). As long as you can retrieve both you'll be fine.

However, if your database is compromised, either due to someone gaining local access or via SQL injection attacks, then both the salt and final hash will be available, which means a brute force attack on the users' passwords would be trivial. To combat this, as suggested by The Rook you can also use a sitewide secret key stored in a file locally as another input of your hashing method so that an attacker would also need to know this to mount an effective attack. Which means your DB would have to be compromised AND the attacker would need access to local files. So using hash(hash(salt + secret) + password), etc.

While in most algorithms you aim to make things as fast as possible, for password hashing you want to slow it down, this is called Key Strengthening (or sometimes Key Stretching). If it takes 0.00001 seconds for your hash function to return, someone can try brute forcing 100,000 passwords a second until they find a match. If it takes 1 second for your hash function to spit out the result, it's not a big deal as far as someone logging into your application is concerned, but for cracking the password it's a bigger deal since each attempt will now take 1 second to get a result, meaning it would take 100,000 times as long to test each brute forced password than it would using your original hash function.

To make your hash function slower, you just need to run it multiple times. For example, you could do new_hash = salt + password + previous_hash 100,000 times. You may need to adjust the number of iterations to a higher value if it's too quick. If you want to be able to change the value later, make sure to store the number of iterations with the user record so that you don't affect any passwords previous stored.

Your user record should now have a field formatted something like this "$<algorithm>$<iterations>$<salt>$<hash>" (or as separate fields if you want).

When the user enters their password you can retrieve the salt and number-of-iterations from the DB and the sitewide secret from a local file and validate that when you run the same number of iterations with the salt and password, the resulting hash matches what you have stored.

If the user changes their password, then you should generate a new salt.

The hashing method you use doesn't matter (but the hashing algorithm does*). Above I suggested hash(hash(salt + secret) + password) but equally it could be hash(hash(salt) + hash(secret) + hash(password)). The method you use doesn't change the effectiveness of your password storage, one is not really any more secure than the other. Relying on the design of how you hash the password and salt together to provide security is called security through obscurity and should be avoided.

*You should not use MD5 or SHA-1 as these are considered insecure. Use the SHA-2 family instead (SHA256, SHA512, etc). (Ref)

like image 193
Rich Adams Avatar answered Sep 25 '22 15:09

Rich Adams


The salt has to be stored with the hash for verification to be possible. Best practice would be to use a different salt each time a password is created or changed.

like image 25
David M Avatar answered Sep 22 '22 15:09

David M


The second alternative is the correct one.

Traditionally, the salt is stored alongside with the hashed password, but non encrypted (typically preappended, for example in unix passwords)

Update: the method used in most newer Unix system is this one.

like image 30
leonbloy Avatar answered Sep 22 '22 15:09

leonbloy