When adding salt values to a hash value for something like a password that cannot be stored in plain text, what is the best place to get the salt values come from? For context, let us suppose this is for passwords on a webpage login.
-
@DevArt, I figured it was better suited here because it requires a very subjective answer. A salt value could be pulled from anywhere, so I am asking "Where do you think is the most secure location to pull salt values from: client or server?"– Morgan HerlockerFeb 21, 2011 at 19:03
6 Answers
I usually have a column created TIMESTAMP
in a user table so I can see when the user registered. I don't like to add an additional column for Salt, so I use the timestamp column as salt:
SHA1(password + created)
-
I am then assuming that when the user signs in again, you pull the date based on the username when you rehash for verification? Feb 23, 2011 at 19:13
-
1@Prof: Yes, in the same way as you do if you have a specific column for salt, so no difference in that perspective.– JonasFeb 23, 2011 at 19:25
Does it matter?
The salt serves two purposes. It makes it impractical to use large tables of prehashed passwords ("rainbow tables") and it makes identical passwords look different in the list of hashes. Making the identical passwords look different helps avoid a problem where several people are using one particular password, which is presumably a common weak one.
Therefore, each account should have its own unique salt, and the salts should not be overly predictable, in the sense that there won't be a group of salts that are likely to occur. (If many sites started at 1 and counted up, bad guys could construct rainbow tables including low-number salts, for example.) They don't have to be random in any sense other than generally unpredictable. They aren't any more secret than the hash itself, so they don't need to be specifically unguessable.
Use any convenient method to generate a salt. If there's lots of potential salt values (early Unix systems frequently used two bytes, for a possible number of 65536) compared to the number of accounts, semi-random assignment would almost never give out a duplicate salt.
-
1I've generally seen the second issue-- identical passwords looking different-- addressed by concatenating the user name, the salt, and the password and hashing the whole string. That eliminates the need to generate a unique salt per account. Feb 21, 2011 at 19:46
-
1@Justin: interesting, I had never seen the username used as part of the hash, but it's indeed a good way to add some entropy. I'd still use a pseudo-random salt though, just because it doesn't cost much to generate one. Feb 21, 2011 at 19:56
-
2@Matthieu With the downside of having to store it somewhere, and if both sides of a transaction need it, having to also send it. With the username, both sides already know it. Feb 21, 2011 at 20:26
-
2@Justin: In which case you're using the user name as a salt. It answers both purposes of the salt: making rainbow tables impractical, and making similar passwords look different. Feb 21, 2011 at 21:12
-
@David - True, you can look at it as the user name becoming part of the salt. I'd still want an additional salt so that the attacker can't use a rainbow table to find the username/password combinations. Without an explicit salt, you're just increasing the size of the string the attacker needs from the rainbow table by the length of the username (which is likely to be short and either completely lower case or completely upper case). A constant salt is sufficient to thwart a rainbow table attack unless your site is large enough that an attacker would generate a site-specific rainbow table. Feb 21, 2011 at 21:31
Each time you want to store a new password (registration, password-reset, password-update), one good technique is:
- generate new salt
- use a cryptographically-secure pseudo-random number generator
- use a decent size salt - a good value is the block size of the underlying hash algorithm (might be SHA-256)
- generate a new password token
- create an hmac function from the underlying hash algorithm (might be SHA-256) using the salt as the hmac key
for i in (0...65536) { password = hmac(password) }
- the result of the iterated applications of the hmac function is the password token
- store the salt and the password token
- do not store the original password
- optionally store the underlying hash algorithm and the stretches for discoverability
Leverage the framework. In .NET you could use the RNGCryptoServoiceProvider...
// If salt is not specified, generate it on the fly.
if (saltBytes == null)
{
// Define min and max salt sizes.
int minSaltSize = 4;
int maxSaltSize = 8;
// Generate a random number for the size of the salt.
Random random = new Random();
int saltSize = random.Next(minSaltSize, maxSaltSize);
// Allocate a byte array, which will hold the salt.
saltBytes = new byte[saltSize];
// Initialize a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
// Fill the salt with cryptographically strong byte values.
rng.GetNonZeroBytes(saltBytes);
}
Other frameworks should have similar classes you can leverage. To achieve randomness software often times employs the user versus Random
as mentioned above. Randomly moving a mouse around in a defined area to provide salt is an option employed by TrueCrypt. It boils down to your specific needs and level of security; since your salt could simply be !@#$%
.
You generate a salt server-side and assign it to a user account upon its creation. Better use some crypto-generation API available with your framework but in principle any sequence will do.
Usually things are stored like this:
User
-------------------
ID
Username
PasswordHashWithSalt
Example:
PasswordHashWithSalt =
A15CD9652D4F4A3FB61A2A422AEAFDF0DEA4E703 j5d58k4b56s8744q
-
Assign it based on what though? Does it not have to come from some value that will remain in place so that it can be replicated when the user signs back in after creation? Feb 21, 2011 at 19:05
-
With "assign" I mean generate a salt per username/password pair (account) and store it in the database. When you need to perform login, you use that stored salt to check things.– user8685Feb 21, 2011 at 19:07
Use bcrypt and read this article as to normal hashes alone is not serious protection in this day and age.
Consider using SDR zero knowledge password protocol which has plenty of opensource libraries and is patent free.
SDR requires salt and the best place to get that is the client; time their keystrokes, mouse movements, hash their environment variables, random numbers, file creation times in their temp folder, to make salt at their end in an unpredictable way away from your server. SDR takes the salt, a large prime, the user password and generates a verifier key. You don't store a password it never leaves their machine but you can verify that they have the password which goes with the verifier key and the salt. It is immune from man in the middle and dictionary attacks. Encrypt the keys and salt in the database column just to be sure.