4

Please read as I did many searches and believe this is NOT a duplicate question.

For your reference, I've read these articles and other questions already:

  1. How do you overcome the problem of the salt being public and known by the attacker

  2. does it matter how random a salt is

  3. Crackstats: Hashing Security

  4. Storing part of the hash outside the database

  5. How to store a salt

Long version of question - story time

Why not just not store the salt? I'm NOT talking about not using a salt. I'm talking about regenerating the salt each time the user logs in and never storing the salt at all anywhere.

This is why I bring it up: We, the group I'm in, is deciding to change the password scheme because we want to move to something better. Someone in the group felt that storing the salt was a security risk for some reason so they decided :

"well, let's just not store the salt. Let's regenerate it each time."

I heard this and thought, "what? why?"

As a reply I got back, "It's a puzzle piece that if they don't have they can't use and so the password is protected."

"ok, how do we generate the salt each time? It would have to be based off of something that will remain constant for the entirety of the user's existence and never change", I said.

"Let's use the user's global user identifier id (aka their user id or guid)"

"But doesn't that make the salt not really random and predictable?"

"We'll add a random component to mix it up."

"But.....then how will you regenerate it each time."

"Well, here is the algorithm:"

For user creation:

  1. On user creation, create a new salt for the user using their guid. Then we do some "magic" with sha512 to "randomize" the salt.
  2. Now we create a password hash by taking the salt from step 1, the password and create a password hash.
  3. Store the password hash, don't store the salt.

For authentication:

  1. We regenerate the salt that we generated above on user creation.
  2. We have the salt now, and the password hash is stored in the database already so we will use bcrypt, or pbkdf2, or scrypt to check the password. (bycrypt i think also generates another salt in some languages automatically so this is another salt that is different from the one that we 'regenerate' each time.)
  3. Now we're safer because look, no salt was ever stored. And the "magic" will only be known to a few of us in the group so it isn't easy to guess.

"But, why do it this way?"

"We want to do something deliberately different from the typical password schemes to add protection." (sounds like security through obscurity to me but I can understand this part. It's an unorthodox approach using algorithms that are considered secure already.

Well, so my question is: is there any merit to NOT storing the salt and instead regenerating it each time? If so, what would be a reasonable way of regenerating the salt? If not, is it because it doesn't add any real security (it's more of security theater or security through obscurity)?

For the sake of simplicity in your answers, lets all limit our answers to the topic of the regenerating the salt each time and not storing it in the database vs storing it in the database and whether this classifies as security through obscurity or security theater or if it's a valid approach.

Here are my views but I would really appreciate your input as well.

Advantages to not storing salt and regenerating it

If attackers accesses just the database, they see that there is no salt. They assume some simple scheme and attack it based on this assumption. They get no results from the attack. They start scratching their head and are stumped. (somewhat, ideal scenario for password protection right?)

Sql injection attacks won't get the salt since it's not in the db, but sql injection is a thing of the past, right? :-) Everyone uses parameterized sql.

Less of a need to encrypt the password hash, even though it's still a good idea. Assuming the somewhat ideal case above.

Disadvantages of regenerating salt

Not really randomized since it has to be based on constant information that we'll store in the database anyway which is virtually like storing the salt.

Relies a bit on secrecy of which user attributes will be used for salt regeneration.

Don't know if 'leaking' the attributes reduces the security of the salt regeneration scheme. I think it does. Say someone is angry and leaves the company and discloses the user attributes being used then an attacker can regenerate the salts themselves which means they can more effectively attack passwords now.

Advantages of storing the salt

Well understood code and less magic to code and test.

Industry standard. As far as I can gather. I guess not many companies come out publicly and say what password schemes they use....do they?

Disadvantages of storing the salt

Visible to attackers. They can more effectively attack each password. (yes, use a pbkdf2 or bcrypt or scrypt for the work factor but at least they have an idea of how to proceed, even if they know it'll take them a while.)

  • FYI, no, I don't know what the "magic" is. I haven't been told and likely won't be told. – Jerry Saravia Aug 07 '15 at 03:25
  • It seems like they are proposing a security-through-obscurity analogue of [pepper](http://security.stackexchange.com/q/41754/49075). ​ –  Aug 07 '15 at 03:40
  • Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/26688/discussion-between-jerry-saravia-and-ricky-demer). – Jerry Saravia Aug 07 '15 at 03:41
  • You are storing the salt in database, and salt is guid in your case. – Cthulhu Aug 07 '15 at 08:52
  • When evaluating the security of a system, assume Kerckchoff principle "A cryptosystem should be secure even if everything about the system, except the key, is public knowledge." Assume that your attacker knows your salt generation scheme; your base system should remain secure even with knowledgeable attacker. Anything you do above that base is security theater. – Lie Ryan Aug 07 '15 at 14:39
  • Someone in your group sounds like they have some personality problems if they won't even share what the "magic" is with you. Don't confuse secrecy with security. – Steve Sether Aug 10 '15 at 11:42
  • Thank you all for the answers. I can only try to show why this approach might not be good. In the end the decision is outta my hands but I really appreciate the discussion. – Jerry Saravia Aug 10 '15 at 14:24

6 Answers6

14

The short answer to your question is, please don't try to be creative when it comes to security. Hash your users' passwords with bcrypt or scrypt, then move on to problems actually in need of solving. A password corpus hashed with either of these algorithms are unlikely to have more than a few of their (weakest) entries broken in the foreseeable future.

The long answer is that whatever "magic" you come up with with SHA-512 is either deterministic, in which case an attacker with your database can produce the same result, or it's nondeterministic, in which case you have the same amount of difficulty producing the correct salt as your attacker. There is a sense to this tactic in that you can force both yourself and an attacker to have to do more work to verify a password hash; if you have 16 bits of entropy in an "unknown" part of the salt, then both you and an attacker must simply try and brute force this component of the password hash; on average, it will take 32,768 tries to discover the correct one. Some of the password hash candidates for the recent PHC incorporated this approach, but I don't believe the winner of the competition (Argon2) does.

That said, even then, you should not attempt to implement this yourself. History is littered with the corpses of well-meaning amateurs who built or tweaked cryptosystems, only to unwittingly introduce catastrophic flaws. There is no reason to expect that you or your coworkers will be immune to this.

Existing solutions are by far good enough, especially when compared against hashing schemes of the past. Modifications you make will at best improve security by an unlikely-to-be-useful margin. The risk of introducing a serious weakness is significantly greater than the reward.

Stephen Touset
  • 5,774
  • 1
  • 23
  • 38
5

Your randomised salt is a "pepper". Add a regular salt as well.

A secret, non-database-stored hash-ingredient is known as a "pepper". (It may be either global or per user. I'd argue, that your pepper is global.) And this is what you are doing.

The justification for peppers is that if someone manages to dump your user database, with all the salts and hashes, then they still won't have the pepper. And the hashes will therefore be useless. This is if they only manage to read out the database. If they also manage to read out the code, then they will have the pepper as well. -- It's a defence-in-depth technique.

Salts are against the shotgun attack against large amounts of password hashes. They don't have to be unknown, just different for each hash. So rainbow tables are useless.

Your concept is pepper-only. But you don't have to play salt against pepper. You can have both. And you should not go without salt. So why not have both?

StackzOfZtuff
  • 17,923
  • 1
  • 51
  • 86
  • 2
    I really don't like the use of the word pepper here. "Pepper" has no agreed-upon meaning in cryptographic contexts, and has been used to indicate a static part of a salt, a secret key used for the HMAC of a password prior to hashing, and for unknown components of a salt. Given that there is no standardized use of the term (or even widespread adoption of the practices each of its meanings refers to!), I don't believe we should promote its use. – Stephen Touset Aug 07 '15 at 17:34
  • 3
    Yes and no. Yes, I couldn't find an actual crypto publication that defines pepper. But I think the term "pepper" is out in the world and there is no catching it. With a quick google I found that people either use it to mean "a secret salt stored elsewhere" or "a secret salt of known bit length stored nowhere" (so to verify it, you must brute force it). -- The part that is common for both definitions is roughly this: "a secret salt that is not stored with the regular salt" (if at all). – StackzOfZtuff Aug 08 '15 at 08:37
4

The salt is not meant to be secret. It is meant to be unique across users in your database (at least).

The reason for this has been mentioned already in that it prevents the attacker from running the brute-force attack on the password hashes against all of the users at the same time.

It does not matter what method you use to make the salt unique for it to achieve its purpose, so revealing it is not an issue. The real goal for the salt is for it to aid in protecting a reused password from a user-wide brute force attack.

It would not even need a rogue employee to reveal a regenerated salt implementation. An attacker with an account in your database already knows what his password is. So he can quickly work out what information the salt would be generated from.

So regenerating it from user data isn't really adding anything to the mix vs storing a salt that can be changed when the users password changes.

John Pettit
  • 161
  • 3
1

What you call "salt" isn't a salt, its just a temporary variable inside the password generation scheme, your actual salt is the user's unique id, which is mostly fine for a salt, salts have to be unique, nothing more.

What you call "magic", is regarded by most people as "pepper", but only if you keep the "magic" actually secret. If you wanted to avoid "security by obscurity", you should keep the algorithm inside version control, and allow your developers to access and talk in public about it, but to have the actual secret value as a key, managed like db passwords. One way would be to do SHA256(uid, pepper), and use it to hash the password with.

If you only use the uid for the password, then your salt is only locally unique, by concept, not globally. Ideally, salts are globally unique. But as you have a pepper, you get global uniqueness for the (uid, pepper) tuple, so what you do is perfectly fine regarding uniqueness.

user10008
  • 4,355
  • 21
  • 33
  • 1
    Actually, salt doesn't just have to be unique, the purpose of the salt is to add entropy to the hashing algorithm, thus salt needs to have sufficient entropy. Salt with low entropy is still better than no salt, but it's not a good salt. – Lie Ryan Aug 07 '15 at 14:29
  • @LieRyan Your statement is incorrect, full stop. Salts do not require *any* entropy whatsoever — in attack scenarios, it is assumed that the value is completely known to an attacker. The purpose of a salt is to ensure that work from an attempt to guess one hash cannot be applied to others. To succeed in this, its one and *only* requirement is to be unique. – Stephen Touset Aug 07 '15 at 17:37
  • 3
    @StephenTouset : ​ Another purpose of a salt is to make most of an attacker's work take place _after_, rather than before, the attacker compromises the database. ​ ​ ​ ​ –  Aug 07 '15 at 18:37
1

I'll keep it as simple as possible (much like security should be).

  • Salts do not need to be private. Salts make two users with the same password have different password hashes to protect against rainbow table attacks. Hiding it using a scheme means you have to keep this scheme private, which will be hard (for example you've discussed it here, and presumably every developer you hire may talk about it with other developers, either during or after their employment).

  • Using the user identifier as a hash means that if the user sets their password to the same as a previous password then an observer can see that this is the case. Salt should be regenerated on every password change

  • If there are multiple instances of your application, any default users may have the same user identifier in each instance (e.g. built in admin account). This makes it possible for an attacker to construct a rainbow table against this salt as they will know the user identifier once they figure out what is going on (believe me, it won't take long). This is why they need to be generated by a cryptographically secure random number generator (CSPRNG).

SilverlightFox
  • 33,698
  • 6
  • 69
  • 185
0

There is no need to generate random salt. The requirement for salt is that it is globally unique. You can derive a globally unique salt from the conditions of a user's login.

For example, if your application requires an email address to log in, you can use: site-specific-prefix:user@email.com as the salt.

The prefix is unique to your application, the email address is unique to the user. Now you have "reasonably globally unique". Which is the only requirement for salt.

Inventing false requirements (salts do not require entropy!) is not a good practice and doing extra "just in case" breaks other guarantees. When we "overdo" security we also incentivize worse attacks.