Question

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.

Was it helpful?

Solution

update: use a competent library e.g. passlib for Python.

These take care of generating a per-password salt and they use a proper hashing algorithm (its not enough to just use a cryptographic hash such as SHA1; you have to apply it in a way that makes it very slow to reverse e.g. looping 1000 or more times over it etc. This is how password hash functions like bcrypt work. Password storing libraries do all this properly; they typically produce a string that is delimited so they can determine the hash system and work factor used; you just store the string without needing to know this.


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 strengthens 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 it's 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.

OTHER TIPS

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.

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.

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.

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.

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.

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: Password hashing, salt and storage of hashed values

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top