I always hear that it is best to use salts on top of stored passwords, which then somehow gets concatenated and hashed afterwards. But I don't know what to use as a the salt. What would be a good salt?
4 Answers
Let's say that you have a table where you'll store the password for each person.
To "save" the password that's being generated, do the following
- get the login from the user
- get the password
- generate some salt from random values. Let's say, from /dev/random (as @Michal suggested), you got "a12bc34de56fg"
- Use some hashing function to generate the hashed password. Let's say the original password was "1password" and you'll use any SHA hashing. You'll do
hashed_password = SHA(SHA(SHA(.... SHA("1passworda12bc34de56fg"))))))))
Store that hashed_password, with the login and the salt, in the table.
login password salt
--------------------------------------
john a7b82783... a12bc34de56fg
And then, to verify when a user access your app:
- get the login and the password
- retrieve the salt for that login from the database (you'll have the salt: a12bc34de56fg)
- concatenate the plain-text-password with the salt and do all the hashing again:
hashed_password = SHA(SHA(SHA(.... SHA("1passworda12bc34de56fg"))))))))
Verify if the hashed_password that you calculated is the same that was stored in the database. You'll know if the password was correct or not.
That's it!. You can get the salt from any random source you like. Why should it be random? Because any non-random salt would make it much easier to to attempt to brute-force your app.
-
6Ideally storing the salt in a separate table/location is preferred however not always possible. The main purpose behind a salt is to make the hashed password (if retrieved) stronger against dictionary lookup attacks (which assume access to the password hash). Commented Oct 12, 2011 at 11:01
The classical recommendation for a salt for password hashing is:
- A random value of 128 bits or more;
- obtained from a cryptographically sound random number generator (
/dev/random
or/dev/urandom
on modern day Unixes); - unique for each entry (i.e. don't re-use the same salt, generate a new salt for each new password);
- stored in plaintext in the database (so that the salt is available when verifying the hash).
There are plenty of past discussions of related topics. And most importantly, you should not implement your own password hashing scheme -- you should use a proven, well tested, peer reviewed implementation (bcrypt/PBKDF2).
-
5Use
/dev/urandom
, not/dev/random
: the former is as fine as one can get for conventional crypto usage (including hashing passwords) and the latter may unduly block. Commented Oct 10, 2011 at 23:04 -
Regarding /dev/urandom/ on Linux, yes I agree, and I think that's also covered in the Wikipedia article I linked to. If that's not clear to someone, then see: security.stackexchange.com/questions/3936/…– user2122Commented Oct 11, 2011 at 7:15
The answer is "almost anything", although some are stronger than others.
Let's assume you are using md5(salt.password).
With no salt, hackers will quickly crack most of the passwords just by looking up the hash in a rainbow table.
Let's say you use "x" as the salt for all your passwords. Many of your passwords will still be found, but fewer. That's because if the password is "p4ssw0rd", then it becomes "xp4ssw0rd" with the salt -- making it slightly harder, but not significantly so.
Now let's say you use "%X88Fc+7" as the one salt for all your passwords. At this point, rainbow tables aren't going to work. But, the consequence of using one salt for all passwords, the hacker will be able to generate a rainbow table with that assumption, and built rainbow tables ahead of time. It's a lot more secure, but not perfect.
The next most secure option is to use the username as the salt, in other words using 'md5(username.password)'. Again, this defeats the standard rainbow table, but a hacker might generate a rainbow table for a specific username (like "root" or "administrator"), so that every time the password is changed, the hacker can do a looking in a rainbow table instead of cracking it again.
So, to be even more secure, choose a different random salt for different users. You have to store this along with the username and password hash. This completely defeats rainbow tables.
Some suggest a "secure" random number generator, rather than something simple. For example, doing an MD5(timestamp+username) when the user creates an account is simple, but not cryptographically secure (since timestamps and usernames are predictable, and thus low entropy). But, since the hacker has a copy of the salt anyway when he steals the database, it's not a problem.
-
Is it safe to store the salt together with username and password hash? If database gets hacked, anyone can see what the salt was and therefore use it to crack the password. wouldn't it be more secure not to include the salt, but rather use something like
'md5(username+"HDJ897#3%"+password)'
? In this case there is no way someone can guess that the salt was totally unique valueusername+"HDJ897#3%"
.– bodacydoCommented Oct 10, 2014 at 22:33 -
The purpose of a salt is to provide a value that breaks rainbow tables, and they perform that job whether or not an attacker has access to them. If you're looking to protect further, you may wish to consider adding pepper. Commented Sep 24, 2016 at 16:51
-
Just been reading crackstation.net/hashing-security.htm, which discusses this in more depth– AndrewDCommented Jun 15, 2017 at 8:14
-
Isn't the salt in "a different random salt for different users" worse than pepper + username? Did you mean a different random salt for each password change?– FaxCommented Mar 8, 2018 at 13:10
For salt just use random bits.
On Linux you can use /dev/urandom
. It is a random number generator based on environmental noise. It's quite unpredictable except for virtual machines. So if you have let's say physical mouse plugged to your box, then /dev/urandom
will give you high quality random bits and is good for salt.
Here is a good article to start with. See also the external references.
Here is an example java code. See how the salt is generated and stored in DB in the createUser()
function. Except for using import sun.misc. ...
it's very good code.