views:

373

answers:

8

My understanding is that a salt is not intended to be secret, it is merely intended to be different from any centralized standard so that you can't develop a rainbow table or similar attack to break all hashes that use the algorithm, since the salt breaks the rainbow table. My understanding here might not be completely correct, so correct me if I'm wrong.

In a widely-used piece of open-source software, the salt would be widely known, and this opens you up to attacks because now they can simply attack the salted version of your hash and create rainbow tables that include the salt data.

As I see it, there are two options to deal with this. The first is to change the salt with every new version of the software, but this is no good because new versions of the software would no longer be able to test against old password hashes.

The second solution I thought of was to have a salt per password stored; in other words, each password gets a different salt. The downside is that the salts have to be associated with the password hashes in some way, probably just by sticking them right next to the password in the database. It might be even okay to use the username (it might not, though, probably usernames are too short).

My question is, is this acceptable? Is there any extra risk associated with storing the salt directly with the password it hashes? It seems to me that storing the salt in the source code is no different, so there's no security loss by storing the salt with the password.

DISCLAIMER: I'm not using this for any real life security system. In fact, I have never designed a password system of any kind. I'm just keeping myself vaguely educated about security issues.

+1  A: 

There was a great article discussing this today, that said use HMAC.

John Paulett
Is there a reason salt + HMAC would be ineffective?
Imagist
Note that this article is not about storing password. It's about the original purpose of HMAC, authenticating messages (signing messages). But of course HMAC is a good choice for storing salted passwords, too.
Lukáš Lalinský
But just to be clear for Imagist, the salt would be part of the input to the HMAC function, so HMAC doesn't mean the salt isn't useful.
Michael Burr
A: 

You actually already have a salt value stored in the user table: the pkey of the table.

You don't have to invent a new column for storing the salt. Just use the pkey. This idea of course presumes that you do have a pkey associated with a user name. e.g. the user name is not the pkey in the table.

This is a near dup wtb: http://stackoverflow.com/questions/1191112/password-hashing-salt-and-storage-of-hashed-values

Paul Sasik
As Lukáš Lalinský says (http://stackoverflow.com/questions/1648464/is-it-okay-to-store-salts-with-hashes/1648516#1648516), the salt really should be random.
Michael Burr
Or you could use some timestamp of when user was created or something else. (because it's longer than pkey)
Janis Veinbergs
@Michael - but as I mention in my comment to Lalinský's answer, that is not correct - salt does _not_ need to be random, just unique for each hash
Cocowalla
@Cocowalla - a relaxed interpretation of the word random, appropriate for psasik's and Lukas's answers, is that random means not derivable from the other data in the row.
Will
@Will: again, I don't believe this matters. The time taken to build a set of rainbow tables is huge (try it!), so all you need is a unique salt per hash.
Cocowalla
How can you suggest people read Bruce and then not understand how useful cracking root:EF45DC23E100CD25 when it occurs on five systems you have access to is?
Will
@Will: A valid point that I had forgotten to consider :) Michael Borgwardt's suggested of also using something unique to the system addresses the issue.I still recommend reading Applied Cryptography, it's just early in the morning and it's been several years since I read it ;)
Cocowalla
@janis: you're assuming straight use of an int pkey. That's not a good salt. A GUID is a great salt and an int could be used as a "good" salt by some derivation such as hashing or by some multiplier equation that makes the number larger.
Paul Sasik
GUIDs contain a random generated element.Expanding something up to more bits by hashing does not, on the other hand, make it a good sort. If there are 4 billion potential input values (e.g. 32 bit), there are still only 4 billion derived hashes even if they are 100000000 bits or longer.
Will
@Will: agreed. Expanding an int is more of an obfuscation.
Paul Sasik
+1  A: 

The salt, by definition, must be random to be effective. Don't use any deterministic value for this. This of course implies that you need to store it in the database along with the hashed password. UNIX systems traditionally even store the hash in the same field as the password (the salt is a fixed-length prefix of the password). In a database, you can have additional column in the users table.

Lukáš Lalinský
This is not correct. The main purpose of salting is to defeat using pre-built hash tables (aka rainbow tables). Each hash's salt should be unique, but need not be random.I highly recommend Bruce Schneier's book, Applied Cryptography:http://www.schneier.com/book-applied.html
Cocowalla
Wikipedia is not The Definite Source. There isn't really any additional benefit you get from random salts over simply unique ones.
Michael Borgwardt
The salt may not need to be random strictly speaking, but it does need to have a high entropy. If salts are similar (they 'cluster') then they don't provide much value. A PRNG is a straightforward way to get entropy, but there are other ways.
Michael Burr
@Michael: I don't think that it matters if the 'cluster' as they will still be unique for each hash - and therefore pre-built tables cannot be used.
Cocowalla
+1 Lukas.@Cocowalla the value of the salt should not be determined by anything else two systems determine it in the same way... see my answer, and consider 'random' in that context.
Will
It's vaguely possible that salts exhibiting regularity might enable an attacker to exploit weaknesses in the hashing algorithm, but extremely unlikely. If you're worried about this, your time would be better spent looking for a hashing algorithm without such weaknesses.
Michael Borgwardt
@Will good point; though a deterministic salt that is guaranteed (or very likely) to differ between systems, such as the domain name, would prevent this as well.
Michael Borgwardt
I must say I don't really get this discussion. Using a unique random salt is currently the best option you can do. We can argue how not necessary it is, but if the best option is also the easiest option, why just not use it? Generating a random number is much harder to screw up than finding a good enough key in your existing data.
Lukáš Lalinský
@Lukáš: Consider that if you generate a random salt you must be able to recreate it whenever you need to check against the stored hash. So that salt must be either stored somewhere, or be derivable.I think the easiest option is to use existing, unique data.
Cocowalla
Storing the random number in your database is definitely easier than determining what is good existing data to use. You don't need to think about it, it doesn't restrict you from altering the existing data in the future, it's a completely standalone solution that just works. If you need to change the existing data used for salts for some reason (and everything does need changing eventually), you can't just rehash the passwords.
Lukáš Lalinský
@Lukas you can lead a horse to water but you cannot make it drink
Will
"If the best option is also the easiest option, why just not use it?" - damn if that isn't a fine quote. It's going on my list.
Michael Burr
A: 

It's perfectly normal to generate a unique salt for each password. The salt may be a product of existing material (such as a UserID, et-al.) or randomly generated. The advantage is that an attack against the encrypted information becomes more impractical as the strength of the salt grows.

Remember: Every cryptographic algorithm is breakable. Information may only be considered "safe" if cracking the protection (via a rainbow table or otherwise) is more costly than the information is worth.

edit:

Presuming you're very new to cryptography, here's a few more tips:

  • Longer salts are better than short ones.
  • The more possible values for a salt, the better. An alpha-numeric salt is better than an numeric one. A binary salt is better than an alpha-numeric one.
  • Salts wont make brute-force attacks less likely against a single password.
Kivin
It's not only perfectly normal for salts to be unique per password - that's pretty much the definition of what a salt is. If the salt isn't different for each password that pretty much defeats the purpose of the salt.
Michael Burr
It does not defeat the purpose completely - using the same salt for the entire database is still much, much better than using none at all, because while there are precomputed rainbow tables for unsalted MD5 and SHA1, there won't be any for a sufficiently long salt. And computing their own rainbow table is not feasible (or at least too expensive to bother) for most attackers.
Michael Borgwardt
@Michael Borgwardt: true, but it is still better to use a unique salt per password. This is trivial to do, so there is little reason not to do it.
Cocowalla
+5  A: 

You can store the salt in 'plain-text' in the table.

  • The salt does not need to be secret to be effective

  • it just needs to be random.

The salt strengths a password by making the hashed value incomparable to the same password in the same or other database, and invalidating large pre-generated lists of common password to hash lookups (e.g. 'rainbow tables').

So its critical that the salt is unique per user and is some random value stored with the password; the alternatives outlined in the question (using the username as the salt, using a single salt value for the whole application) each fail:

  • if systems use the user-name or other trivia, then the password can be compared to other users with the same name in other systems (imagine how often the 'administrator' or 'root' user account uses the same password in different systems...)

  • if the system uses a single random salt for all users in the same system, then two users who by chance have the same password would have the same hash, and guessing one user's password would trivially compromise the other.

Will
As I mentioned in my other comments, you need to choose a unique salt per hash. I fail to see any benefit in making it random?Regarding your first point "if systems use the user-name or other trivia..." - if a unique hash per user is used (e.g. primary key or username), then this is not an issue.
Cocowalla
@Cocowalla "unique per user"=="unique salt per hash". And you claiming you can use the username is failing in the first fail bullet point above as shown in my example.
Will
@Will: Fair point :)Michael Borgwardt suggested also using something unique to the system - if you concatenated that to the unique per user hash, that will get around the issue.
Cocowalla
@Cocowalla: then you are just pushing the problem into the dark corner case of what if a user is removed, then recreated. Its a small dark corner, but its there. Just go with a random value stored in the password database with the password hash and be done with it! Its how the professionals who have read Bruce do it ;)
Will
@Will: OK, I concede - it appears there are benefits of using a random salt and storing that instead of using existing data.
Cocowalla
A: 

Your second solution "Have a salt per password stored" is the right one and typically used.

The "Salt" is primarily there to make it difficult to detect when two users have the same password - so you mix a known "Salt" into the password. The salt needs to be gettable at password check time.

So typically either you generate a random salt and store it with the password OR you use some other identifier (user ID, username etc) as the salt.

MarkR
"The "Salt" is primarily there to make"... I would consider this a secondary benefit of the salt. Its principle use being for reducing the probability of a successful attack.
Kivin
+2  A: 

Trying to keep the salt secret is pointless, because the entire practice of salting and hashing passwords exists only because we know from experience that we can't even keep our databases secret with complete reliability. You can at most store the salt separately and hope that an attacker who gets access to your DB does not find it, but if you used a good hashing algorithm and long enough individual salts, you should be safe either way.

The point of a salt is solely to ensure that you cannot amortize the cost of a brute force attack across an entire database or even multiple databases.

The first is to change the salt with every new version of the software, but this is no good because new versions of the software would no longer be able to test against old password hashes.

A variation of this that I have seen is to generate a random salt during installation (and of course keep this across versions) so that each running instance has a different one. Of course, having a different salt for each password (perhaps in addition to the above) is better yet.

Michael Borgwardt
+1: "The point of a salt is solely to ensure that you cannot amortize the cost of a brute force attack across an entire database or even multiple databases."Very succinct.
Kivin
A: 

Using a single salt for all passwords in the database is helpful, but much less secure than giving each user a unique salt.

Basically: a longer (in bytes) password+salt increases the search space, and thus makes it harder to use "stock-standard" rainbow tables.

However, if the same salt is used for all entries, then it is possible to create a rainbow table specifically to attack your software. If your userbase is large then someone might decide to make such a rainbow table.

For example, if you simply add " and a lot of salt" to the end of each password before hashing, an attacker could construct a table of hash values generated by lots of strings, all those strings ending with " and a lot of salt".

For this reason, a per-user salt is the best way to go. However, remember that you also want the password+salt to be "long".

If you want to use the primary key, it's probably a good idea to take the hash of the primary key rather than using the primary key itself, because if the password+salt for user 43 looks like "myPassword00000000043" then an attacker could build a table with the assumption that there are a lot of zeroes in the middle. Creation timestamps and random string are probably better options though, as PKeys can sometimes be easily found or guessed.

Note: I'm not a true encryption expert, don't use this advice in a real system.

Artelius