26

First of all, my motive is to avoid storing the salt in the database as plain text. As far as this question is concerned, the salt is not stored in the database.

After discussion in comments and in chat, I've come up with a theory:

It appears that using doman_name + user ID alongside a pepper will provide a sufficient combination of randomness and uniqueness.

Would a method such as this provide just as much security as a random salt without having to store a designated salt in the database as plain text?

  • Calling a hash like sha-256 will not generate any entrophy at all. The number of possible inputs will fix the number of possible hash-values. – martinstoeckli Sep 01 '13 at 19:09
  • If the input is unknown (like a password), isn't there entropy? –  Sep 01 '13 at 19:27
  • Ummm I think I asked this already http://security.stackexchange.com/questions/33860/how-does-hashing-work – Griffin Nowak Sep 01 '13 at 20:10
  • 1
    @Griffin - I think the OP's question actually is: "Can storing a salt be avoided completely, derriving the salt from userid, constant text, and the password itself". – martinstoeckli Sep 01 '13 at 20:16
  • @martinstoeckli Wait he wants the derive the salt every time? And whats the point of even hashing if he stores the password and id as plain text? – Griffin Nowak Sep 01 '13 at 20:18
  • Or does he just want 1 salt that gives him both the user name and the password? – Griffin Nowak Sep 01 '13 at 20:18
  • @Griffin I want a salt that can't be guessed and is unknown without having to create another field in my database for it. If I use the password (unknown) and user ID (unique per account) and domain name (unique per website) and it's just as secure as some random plain text string, why not go with the first method? The first method requires one less piece. –  Sep 01 '13 at 20:21
  • @Griffin - There would be no need to store the plain text password, because when you verify the password all necessary information is available, the userid, the constant text and the just entered password. – martinstoeckli Sep 01 '13 at 20:23
  • @MisterMelancholy Okay. – Griffin Nowak Sep 01 '13 at 20:24
  • @MisterMelancholy "unknown" "entropy" I think you need to check the definition of "entropy". It does not mean "I don't know the answer", it is bound on the probability of correctly guessing the answer with *x* tries. *Practically, a lot of entropy means you cannot guess the correct answer, ever, even if you try as much as you can in a lifetime.* – curiousguy Sep 01 '13 at 23:49
  • @curiousguy I read [this explanation of entropy](http://security.stackexchange.com/questions/21143/confused-about-password-entropy). I originally thought it meant "randomness", but it appears to mean "the level of randomness". I've updated my question to reflect this (I think). Thanks for the input –  Sep 02 '13 at 03:07
  • 1
    See also http://stackoverflow.com/q/536584/10080. There are some interesting aspects to consider. – AviD Dec 12 '13 at 10:27

6 Answers6

28

The only requirement of a salt is to be globally unique. It doesn't have to be random and it most certainly does not have to be unknown.

Note the keyword globally. A salt must be unique not only in the context of your database, but in the context of every single database out there. An email or an incremental user ID is (very) unlikely to fulfill this requirement. Using a randomly-generated salt does.

EDIT

I'm going to address the whole using a domain + userid as a salt idea that came up in the comments. I do not think this scheme is a good idea especially when compared with just using a random salt.

If your site is a high target one, an attacker might find it worthwhile to generate a rainbow table targeting the admin account before the attack occurs. This might allow him to get access before the attack gets discovered. The domain + userid scheme does not work well when you consider this situation because the admin account is usually within the first few userids in the system especially when userid is incremented using a counter.

That being said, this whole discussion is really moot in practice. Generating random salts is easy and fast. Many password hashing libraries, especially the bcrypt ones already do it for you. There really isn't a point in rolling your own scheme even if it's just as secure. Let's face it, we are all lazy people aren't we? :P Why reinvent the wheel?

jus1in
  • 5
  • 2
  • 1
    Technically, using unpredictable salts does provide a minor benefit, since it prevents an attack from starting a brute-force attack _before_ they've compromised your password database. But you're right about (global) uniqueness being much more important. – Ilmari Karonen Sep 01 '13 at 13:13
  • Also, if you don't want to use random salts for some reason, the global uniqueness requirement _could_ be satisfied e.g. by combining a locally unique per-user value (e.g. an e-mail address or a user ID number) with a globally unique system ID (e.g. the domain name of the website). – Ilmari Karonen Sep 01 '13 at 13:16
  • An email would probably fail to provide over-all uniqueness, but what about user ID? What are the chances that a user, across 3 or 4 small websites with 100+ users and 10+ websites with 10,000 users will have the same user ID across any 2 of those websites? I'm not saying that it's impossible, just very unlikely. Also, why is this even a requirement? If a hacker has a user's password, won't they try the existing password before bothering to crack it, regardless of the hashes matching? If the passwords are different, they'll have different hashes anyway. –  Sep 01 '13 at 17:41
  • 3
    @MisterMelancholy The point of having a globally unique salt is so that the attacker cannot generate a rainbow table before hand. –  Sep 02 '13 at 00:52
  • I refer you to [How to store salt?](http://security.stackexchange.com/questions/17421/how-to-store-salt/) for a nice long description of exactly why salts are required, and what properties they need. – Polynomial Sep 02 '13 at 12:33
  • @Polynomial Engaging in a little self-plugging are we? :P –  Sep 02 '13 at 12:40
  • 1
    @TerryChia Only where appropriate! ;) – Polynomial Sep 02 '13 at 12:43
  • Ok, I think I understand now. A salt is to provide per-hash uniqueness, but it's [seldom-used counterpart](http://security.stackexchange.com/questions/41754/what-is-the-purpose-of-a-pepper/41757?noredirect=1#41757) is what provides a random and unknown factor to a hash if needed. If you edit your answer to add that `domain + user ID` would be enough for a viable salt and that using a pepper would provide a random and unknown effect if needed, then I'll accept this as the answer. Also, sorry that the question changed since you posted your answer; it seemed to have grown alongside my curiosity. –  Sep 04 '13 at 06:20
  • @MisterMelancholy I will not edit my answer to include that because I do not believe that scheme is a good one. Being unpredictable is not a hard requirement of a salt. However, if your application is a high value one, it might be worth it for an attacker to generate a rainbow table for the admin user or a few high value targets. using `domain + user id` will not be a good idea when you take this into account as the admin accounts have a high tendency to be `userid=0` or `userid=1` when you using incrementing user ids. Just generate a random salt, it's the easiest and least painful way. –  Sep 04 '13 at 06:27
  • @TerryChia I didn't know you'd disagree, now it looks kind of like a bribe. I respect where you're coming from in not wanting to change your answer for rep. Anyway, back on topic. What about using a long and random pepper in addition to a salt? Are you simply saying that using a random salt is easier? I'd like an accepted answer to make a statement about that, even if the answer says it'd be more troublesome to implement than a random salt. Even though I've updated my question a lot, it's always been asking _if this method is as secure_, not necessarily as easy to implement –  Sep 04 '13 at 06:46
  • @MisterMelancholy I have added in some points addressing the issue. –  Sep 04 '13 at 06:57
  • @TerryChia What about using a long and random pepper with a predictable salting scheme? Does that not change your view on the scheme at all? My question was updated to address the possibility of adding a pepper. –  Sep 04 '13 at 07:03
  • @MisterMelancholy My answer to that will be *I don't immediately know*. It does appear to solve any worries with a predictable salt but there might be some more subtle weaknesses I can't think of. My last point still stands though, randoms salts are easy and fast to generate. Why use something else in practice? –  Sep 04 '13 at 07:09
  • @TerryChia I just like to ask questions. And my theory appears to be a _valid_ theory. I don't think I'll be cryptographically (dis)proven here, so this answer will have to do. Thank you for your time and extended input. Also, as far as me changing my question a lot goes, I'm asking about these kinds of situations and how to avoid them [here on the meta](http://meta.stackexchange.com/questions/195694/question-editing-or-question-reforming) if you want to provide input. –  Sep 04 '13 at 07:39
  • If the domain+userid scheme is implemented correctly, then the uniformity of the userid across databases isn't a problem: the attacker can't build a rainbow table for e.g. userid=1. Of course, that assumes *implemented correctly*. If salt = domain||userid, that's broken. If salt = sha1(domain||userid), that's ok. In any case, @MisterMelancholy should just call a standard function and not try to reinvent a wheel and wiggle between a square one and a pentagonal one. – Gilles 'SO- stop being evil' Sep 04 '13 at 15:42
11

The important feature of a password salt (as Terry Chia correctly notes) is that it should be globally unique: no two password hashes (even on different sites) should ever have the same salt.

Using unique salts protects against various related attack methods that might be employed by an attacker who has compromised the user database and wants to recover the passwords from their hashes:

  • First of all, it prevents an attacker from easily telling if several users have the same password (which would make those users obvious target, since such a common password would likely be easy to guess and provide a high payoff).

  • Conversely, it also prevents an attacker who has compromised multiple sites from being able to easily tell which users have used the same password on both sites.

  • Further, using a unique salt for each user prevents an attacker from obtaining any benefit from attacking multiple accounts at the same time. Without salts (or with non-unique salts), an attacker could hash a guessed password and then compare it against every password hash in the database, making it more likely that they'll obtain at least one match. With unique salts, this is impossible, since the attacker has to choose the salt (and thus a single target user) before hashing each password guess.

  • Finally, unique salts also make it impractical to use precomputed hash look-up tables (like the so-called "rainbow tables") to speed up password cracking, since, essentially, a separate table would be needed for every user.

Basically, the main goal of salting is to ensure that an cracking multiple compromised password hashes together should be no easier than cracking each one of them separately — nothing more and nothing less. Using globally unique salts achieves this goal.


One easy way to ensure global uniqueness (with high likelihood) is to use a sufficiently long random string as the salt. However, other ways exist too.

For example, you could obtain a globally unique salt by combining a locally unique user identifier (such as an e-mail address or an account number) with a fixed, globally unique site identifier (e.g. the domain name of a website), and possibly some other items like a purpose designator (in case you might need more than one unique salt per user) and a timestamp (so than a new password will always get a different salt). For example, the following string would be perfectly good globally unique salt:

"This is a password salt for user 5457 on security.stackexchange.com created at 1 September 2013 13:35:23.94730 UTC"

and so would this one too:

"password_salt:5457:security.stackexchange.com:20130901T133523.94730"

If you'd prefer your salts to be more compact, you could also feed either of the strings above through a cryptographic hash function like SHA-256 and use the output as the salt. Or, if your system provides a built-in GUID generator, you could just use that (assuming that it works as it should, of course).


All that said, there is one potential benefit to making password salts not only unique but also unpredictable: it prevents the attacker from starting a brute-force attack before they've compromised your database.

Basically, if I, as an attacker, knew that your admin account's salt was, say, "12345678", then I could set my computer(s) to compile a lookup table of more or less common passwords hashed with that salt even before I'd found a way to obtain your actual password hash. Once I did find a way to do that (maybe weeks or months later), I could look up the hash in my table, hoping that it might match one of the passwords my program had already tried in the mean time, in which case I would know the password immediately.

However, if I didn't even know what the actual salt you used was, I wouldn't be able to start guessing the password before I first obtained the correct salt. That would take extra time, potentially allowing you to change the password before I managed to crack it.

Again, long random salts are (with high probability) not only unique but also unpredictable. That said, there are other ways to achieve this goal, too. For example, you could take either of the unique example salts shown above and just append some secret value (e.g. a random string stored in a config file, possibly changed regularly) to it. Since this secret would be the same for all users, it wouldn't help with uniqueness, but it would ensure that I wouldn't be able to start a brute-force attack without first somehow learning the secret.


Addendum: Regarding your edits to the question, I'd say that your scheme (using domain name + user ID + pepper as the salt) should be enough. If possible, I'd also include a timestamp, but that obviously requires you to store the timestamp somewhere.

That said, I still find your premise ("the salt is not stored in the database") a bit puzzling. If you can store the password hash itself in the database, why not the salt too?

In fact, many common password hashing schemes don't use a separate database column for the salt at all, they just store it as part of the hash string, e.g. as method$salt$hash, where method identifies the hashing method used, salt and hash are the salt and hash values encoded using some suitable scheme (e.g. base64) and $ is just an arbitrary separator character that doesn't occur in the encoded salt or hash.

Ilmari Karonen
  • 4,406
  • 20
  • 28
  • I'm not asking about using a known salt (like domain name + user ID), I'm talking about using salts that contain user-defined values that you can't see without logging into the account in the first place (like email, or user password itself). This prevents pre-computed rainbow tables for specific users, and keeps me from having a `salt` field in a database table. Wouldn't that be beneficial because a hacker couldn't immediately hashing if the database was compromised? –  Sep 01 '13 at 17:48
  • Using the password as (part of) the salt doesn't help anything. Think about it a bit and you'll see why. (Hint: How is the salt used in password hashing?) Using some user-specified value _that the attacker cannot guess_ could indeed help make the salt unpredictable, but things like e-mail addresses can often be pretty easy to guess -- people tends to post them all over the web. You really should just store the salt in the database, either in a separate column or (as is common) just prepended to the password hash. – Ilmari Karonen Sep 01 '13 at 18:25
  • Using a password as part of a salt looks perfectly viable to me: It'd be "password + password". Alone, it'd be a bad salt because it's not unique, but when doing something like "user ID + - + password + password" would be unique and unknowable, correct? Note that the hyphen is needed for cases where user ID 1 uses the password 23, and user ID 12 uses the password 3. –  Sep 01 '13 at 18:45
  • 2
    @MisterMelancholy: Why do you think an attacker would have any more difficulty creating a lookup table for `userID + password + password` than for just `userID + password` (with or without delimiters)? – Ilmari Karonen Sep 01 '13 at 19:01
  • @MisterMelancholy - To double the password would help nothing at all, this would be just another hash algorithm. It would not even add a server side secret (the algorithm), since the salt is normally stored plaintext. You could then build 1 rainbowtable to recover all passwords of your database. – martinstoeckli Sep 01 '13 at 19:01
  • @IlmariKaronen Why would an attacker have any more difficulty creating a lookup table for `salt + password`? Is it because salt holds some level of entropy? What about using a sha-256 of `user ID + - + password`? And the point of the delimiter is to ensure uniqueness. –  Sep 01 '13 at 19:15
  • @martinstoeckli well, the benefit of asking this question is to avoid storing the salt in plain text in the database; there are hashing functions that do not add the salt in plain text. Also, a hacker could make a rainbow table for all 150-character phrases, which would long enough to contain most salts and passwords combined. The only reason they don't is because that'd be a massive table. The salt is just a unique prefix before hashing so that the hash is different, is it not? –  Sep 01 '13 at 19:20
  • I've updated my question a number of times (and am done), and though it's asking the same basic principle, I'm now asking each person with an answer to consider revising their answer to make sure it's still on-topic to the question. Sorry for my indecisiveness, and thank you for your time and input. –  Sep 04 '13 at 06:53
4

A salt is supposed to be unique, must be long enough, and should be unpredictable. Randomness is not necessary, but it is the easiest way for a computer to meet those requirements. And it is not the purpose of a salt to be secret, a salt fulfills its purpose even when known.

Uniqueness means that it should not only be unique in your database (otherwise you could use a userid), it should be unique worldwide. Somebody could create rainbowtables for salts like e.g. 1-1000 and would be able to retrieve passwords for all accounts with those userids (often admin accounts have low userids).

Long enough: If the salt is too short (too few possible combinations), it becomes profitable again to build rainbow-tables. Salt and password together can then be seen as just a longer password, and if you can build a rainbow-table for this longer passwords, you also get the shorter original passwords. For very strong and long passwords, salting would actually not be necessary at all, but most human generated passwords can be brute-forced because they are short (people have to remember them).

Also using salts derrived from other parameters can fall into this category. Only because you calculate a hash from the userid, this doesn't increase the possible combinations.

Unpredictability is a bit less important, but imagine once more the case that you use the userid as salt, an attacker can find out what the next few userids will be, and can therefore precalculate a narrow number of rainbow-tables. Depending of the used hash-algorithm this can be applicable or not. He has a time advantage then, can retrieve the password immediately. More of a problem will be, if the admin accounts used a predictable salt.

So using a really random number, generated from the OS random source (dev/urandom), is the best you can do. Even when you ignore all reasons above, why should you use a derrived salt when there is a better way, why not use the best way you know?

UPDATE: to answer the changed question:

Using only domain_name + user_id to generate the salt is surely not a good idea, because it can be guessed and makes it predictable. A pepper won't help here, because it is as constant as the domain_name, you should not rely on it to be secret. With the user_id you gain uniqueness, with the domain_name you get global uniqueness, but you are missing the unpredictable part.

In your previous example you added the password itself as random parameter like salt = hash(domain_name + user_id + password). This could work as long as the salt won't be stored at all, to verify the password you would have all necessary parameters. I cannot see a flaw in this concept, but this doesn't mean that i recommend it. As already mentioned, you cannot do better than generating a random independend salt. Adding this salt to the hash and extracting it for verification is not a hard job, most appropriate hash functions will already do it for you, because they also have to store the cost factor in the same way.

martinstoeckli
  • 5,189
  • 2
  • 27
  • 32
  • Technically, as long as each salt is globally unique, their length doesn't matter. (And conversely, just making your salts longer doesn't help if they're not unique.) Salting doesn't really help much against brute-force attacks targeted against a _single_ user (as the middle part of your answer would seem to suggest); for that, you want [key stretching](http://en.wikipedia.org/wiki/Key_stretching). – Ilmari Karonen Sep 01 '13 at 13:22
  • @IlmariKaronen - Just wrote a bit more clear what i meant (about the middle part), probably you didn't notice the edit. And of course key-stretching is a must today. – martinstoeckli Sep 01 '13 at 13:24
  • Salting with user ID would be unique for a single database. The chances of the same user having the same ID across 2 (or 3 or 4) websites is likely very low. If a hacker pre-computes a rainbow table with IDs 1-1000, the hash is vulnerable because you used a predictable salt, and is why I stated in my question that salting with the user ID alone is not a good idea. –  Sep 01 '13 at 17:31
  • 1
    @MisterMelancholy - It doesn't matter, whether a user has the same id on another site, a rainbow-table with those salts would contain "all" passwords with all of the choosen salts, thus working for every site. About the email, you cannot presume that the emails are hidden from the public, hashes are made or the case, when the database is already stolen, so the email addresses will be known as well. Using the email as salt, maybe combined with other data and hashed, is not the worst thing you can do, but using a random independend salt is always better. – martinstoeckli Sep 01 '13 at 18:52
  • @MisterMelancholy - You already answered it well. The hash is used to make it impossible to retrieve the original password, so storing the password as salt in a retrievable form will undo the whole effort (you need it for verification). If you want to add a server side secret, a good method is, to encrypt the password-hash with a server side key, or to use a pepper. But don't mix up the two, let the salt be known (plaintext) and the server-side key be a secret. – martinstoeckli Sep 01 '13 at 19:21
  • Sorry, I removed my comment because I basically asked the same thing on the answer by ilmari Karonen and you replied to it. Also, the whole point of asking this question is to avoid the need to store the salt in plain text in the database. There are functions for hashing passwords that to not append the salt to the password. I know there is a separate salt and pepper, but what's wrong with having them both be the same thing if possible? @martinstoeckli –  Sep 01 '13 at 19:24
  • @MisterMelancholy - Ok i understand now, you don't want to store the salt at all, and therefore want to derrive the salt completely from other parameters. There is one problem though, it will make it impossible to change the parameters afterwards. When the user wants to update the email and you used it as salt, you cannot recalculate the password-hash with the new email, because you do not know the original password then. You would have to store the old email as well, what makes it no better than storing a salt. – martinstoeckli Sep 01 '13 at 19:32
  • Yeah. I should probably put that in my question so that it's more clear - sorry for the confusion. And that's simple; If a user wants to change their email, re-hash the password since the salt will be different and update both fields at the same time. If a database gets compromised, users changing their passwords would also change the salt, thus changing a potentially hashed version of the password that provides entropy because the original value is unknown, thus creating a new and random salt. –  Sep 01 '13 at 19:37
  • @MisterMelancholy - You _cannot_ rehash the password when updating the email address. To create the new password-hash you need the email and the original password, but at this moment you know only the email and the _hash_ of the original password. – martinstoeckli Sep 01 '13 at 19:41
  • Then have them provide their password to change this field? Even so, using anything that the user can change as part of the salt will likely be a bad idea. However, IDs will never change, and if the password changes, their changing their password. I'm going to update my question and make it a little more in-depth with relevance to what we're discussing here. –  Sep 01 '13 at 19:47
  • @martinstoeckli Updated my question. And thanks for the discussion so far. –  Sep 01 '13 at 20:00
  • I've updated my question a number of times (and am done), and though it's asking the same basic principle, I'm now asking each person with an answer to consider revising their answer to make sure it's still on-topic to the question. Sorry for my indecisiveness, and thank you for your time and input. –  Sep 04 '13 at 06:53
  • @MisterMelancholy - I updated my answer accordingly. – martinstoeckli Sep 04 '13 at 07:26
3

First of all, my motive is to avoid storing the salt in the database as plain text.

Why? There is no good reason to avoid storing the salt in the database in plain text. This is how a salt is normally stored.

With the various iterations of your question, you've proposed various ways to do things differently, but they all either end up having the same security properties, or (usually) make things worse.

The point of a salt is to prevent attackers from sharing the work when cracking many accounts at once. Often attackers are not after a particular user on a particular site, what they want is to get a foothold or to crack as many accounts as possible. The point of salt is to make cracking Joe's account on the ACME site require completely different computations from cracking Jane's account or Joe's account on the Yoyodyne site. Hence the need for a salt to be globally unique: across accounts, and across databases (and even across time).

If you use the password as part of the salt calculation, it isn't a salt at all. The salt needs to be independent from the password. If you calculate the salt from the password, then it becomes part of the hash function: H(S(P),P) is a function of P, you've only created a new hash function H'(P) = H(S(P),P).

Using the user name is not good because it can be the same across databases. An attacker with the ACME database and the Yoyodyne database can crack both databases without duplicating the effort if they use salt that is derived from the user name.

If you use the domain name and the user ID, that can work. Make sure that no one else in the world who uses the same domain name; in particular, don't use the same domain name if you have more than one subsite: include the service name or whatever it takes to make the name unique. Also, don't reuse user IDs. As long as your salt is globally unique, it's a proper salt.

Note however that you will not gain any security from using the domain name and user ID as the salt rather than a random salt as is typically done. The salt is still effectively stored in the database, just in some weird way. You save a few bytes per database record, which shouldn't be significant.

A pepper does not significantly improve security either. You cannot assume that your pepper remains secret. If the attacker has been able to obtain a copy of your password database (typically by compromising your application or by gaining access to a backup), it's likely that they also have access to the pepper (it needs to be accessible to the application and backed up, after all). The only case where a pepper is useful is a compromise such as SQL injection which only grants the attacker access to the database and does not extend to an application compromise, not even via an administrative account. Don't count on it. Even if you use a pepper, your salt must be globally unique.

I strongly recommend generating a random salt and storing it alongside the password. Preferably, don't code it up yourself: use an existing library that does it right. The more you deviate from recommended practice, the more you risk doing it wrong — perhaps completely, dangerously wrong like deriving the salt from the password.

Remember that in addition to be salted, password hashes must be slow. That means PBKDF2 or bcrypt or scrypt, with an iteration count adjusted for current computer speeds.

For more background, read our numerous threads on this subject:

Gilles 'SO- stop being evil'
  • 51,415
  • 13
  • 121
  • 180
  • "you will not gain any security from using the domain name and user ID as the salt". Isn't the point of the salt to "to prevent attackers from sharing the work when cracking many accounts at once"? The salt alone isn't supposed to increase security; it's so that a hacker can't re-use their work for one hash on another. And "You cannot assume that your pepper remains secret." I find this argument kind of a moot point. If a hacker gets server access and finds your password hashing function, aren't you equally screwed whether you're using bcrypt or something else? with or without a pepper? –  Sep 04 '13 at 08:26
  • 1
    @MisterMelancholy I meant in comparison with a random salt, not in comparison with no salt at all. Domain name + user ID is roughly as secure as a random salt, if you do it right (but has no advantage). The attacker can get the application code without getting access (e.g. from a compromised backup), it's a fairly common scenario that you should protect against. Furthermore you should protect the passwords themselves even if the attacker gains access to the accounts, because the passwords may be reused elsewhere. – Gilles 'SO- stop being evil' Sep 04 '13 at 08:30
  • I think it has an advantage; it means one less field in my database as well as not having a designated "salt" field. Without source code, the hacker is even more lost than they'd be with a salt field. Also, "The attacker can get the application code without getting access (e.g. from a compromised backup)" Isn't this just as likely to hold the password hashing function as it is to hold the pepper? –  Sep 04 '13 at 08:37
  • @MisterMelancholy The salt is usually stored together with the hash, this is standard practice, but you can have a separate salt field (and iteration count or analogous work factor value, that needs to be stored as well). The password hashing function doesn't need to be secret. Never assume that the hacker doesn't have the source code: if your security depends on that, you've already lost. This is a [well-known security principle](http://en.wikipedia.org/wiki/Kerckhoffs%27_principle). – Gilles 'SO- stop being evil' Sep 04 '13 at 09:13
  • 1
    @MisterMelancholy - You use a slow hash like BCrypt and a pepper, exactly for the case a hacker gets access to your database or server. If the hash function is slow, an attacker can calculate e.g. only 1 hash instead of [8 Giga](http://hashcat.net/oclhashcat-lite/#performance) hashes. The pepper requires the attacker to have privileges on the server, what is more difficult than just having read access to the database. – martinstoeckli Sep 04 '13 at 11:32
2

Since none of the other answers seem to touch on this:

DO NOT use part of the password as the salt. In addition to decreasing unpredictability, it will, when an attacker figures it out, help an attacker break the passwords. Why? Because they have part of it right there, next to the password in the database.

Update: If you are using part of the password in the salt, and you want to avoid having to store the salt, then pulling part of the password after it's entered to calculate the salt will work well. It further complicates brute forcing, and it's just as effective as a regular salt at increasing entropy. It makes rainbow tables a bit harder to make, as you need to calculate the salt per password, but it doesn't really prevent them any better than a regular salt.

demize
  • 255
  • 1
  • 10
  • "First of all, my motive is to avoid storing the salt in the database as plain text. I'd like to avoid "that's bad because the salt is stored in plain text" kind of responses." –  Sep 01 '13 at 20:30
  • 2
    @MisterMelancholy Yet this is the most important point. If you don't store the salt, it becomes part of the hash function, thus is no salt at all. If you do store the salt, you need to protect it, since it contains the hash — and you'll need a way to retrieve the salt, which will be equally usable by an attacker. – Gilles 'SO- stop being evil' Sep 01 '13 at 20:32
  • But the hash generated for the salt won't be stored in the database. That's the whole point of this question. There will only be one hash stored in the database. The only way they could find the hash for your salt is to crack the original password hash, thus making it irrelevant that the salt hash holds the password because they'll have the password by the time they get the hash. The salt hash will be generated on-the-fly why whatever server langauge, and should be used for nothing more than for entropy and length to your salt. @demize –  Sep 01 '13 at 20:41
  • It is not stored. The reliable way of re-generating it is using the password that's being hashed in the first place. Also, the only reason I've ever heard "a salt does not have to be protected" is because of stupid policies I don't agree with (hence this question). A salt is just a recyclable and unique pepper, which is stupid because this method could provide every possible purpose of a salt and a pepper combined if it's treated as a salt and pepper combined. Also, it's true that this opens another attack vector, however, you must pass the first attack vector to get to it. @demize –  Sep 01 '13 at 20:53
  • @demize - Well that's the actual question, does it really introduce a new attack vector and how? The userid would make the salt unique, the domainname would make it globally unique, and the password would make it unpredictable. It is possible to regenerate it, and when the password changes, it would result in a different salt. – martinstoeckli Sep 01 '13 at 20:55
  • let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/10420/discussion-between-curiousguy-and-demize) – curiousguy Sep 02 '13 at 02:21
  • I've updated my question a number of times (and am done), and though it's asking the same basic principle, I'm now asking each person with an answer to consider revising their answer to make sure it's still on-topic to the question. Sorry for my indecisiveness, and thank you for your time and input. –  Sep 04 '13 at 06:53
1

In addition to @terry-chia's outstanding answer there is another reason to pick random salts. The hashing and authentication scheme that you are using today may place relatively weak requirements on salting, but someday you might (or a successor) might modify the scheme used in a way that does have a randomness requirement.

So although randomness isn't a requirement, you are far safer if you do pick random salts, as that will guarantee that you get all of the things required for your scheme today, but it will also provide you with what you may need tomorrow.

Again, an additional, reason on top of what others have already explained. Do not derive the salt from user data! Using a random salt may get you more than you need, but it will ensure that you don't make other errors. You have nothing to gain in not using a random salt (unless there is something you haven't explained yet), while you make your system far less robust by just going for the minimal requirements of a salt.

Jeffrey Goldberg
  • 6,420
  • 17
  • 21
  • I've updated my question a number of times (and am done), and though it's asking the same basic principle, I'm now asking each person with an answer to consider revising their answer to make sure it's still on-topic to the question. Sorry for my indecisiveness, and thank you for your time and input. –  Sep 04 '13 at 06:52