7

I realize that this topic have been brought up sometimes, but I find myself not entirely sure on the topic just yet.

What I am wondering about how do you salt a hash and work with the salted hash? If the password is encrypted with a random generated salt, how can the we verify it when the user tries to authenticate? Do we need to store the generated hash in our database as well?

Is there any specific way the salt preferably should be generated? Which encryption method is favored to be used? From what I hear sha256 is quite alright.

Would it be an idea to have the hash "re-salted" when the user authenticates? And lastly is it any major security boost to rehash it a bunch of times?

Thank you!

Henrik O. Skogmo
  • 2,013
  • 4
  • 19
  • 26
  • Speaking of security boosts - check your site for SQL or file injections. When done fixing them, proceed to xss ones. – Your Common Sense Jan 02 '11 at 14:01
  • [How to use the PHP 5.5 password hashing functions](http://www.dev-metal.com/use-php-5-5-password-hashing-functions/) – Sliq Sep 13 '13 at 23:57
  • Also see Openwall's [Portable PHP password hashing framework](http://www.openwall.com/phpass/) (PHPass). Its hardened against a number of common attacks on user passwords. – jww Oct 11 '14 at 23:33

5 Answers5

7

The answer is to not do it yourself. The one-liner that will do everything you need in PHP is to use bcrypt.

Read this, it's easy to understand and explains everything you asked: http://codahale.com/how-to-safely-store-a-password/

bcrypt takes into account the hashing by itself, and can be configured to be as "complex" as necessary to maintain the integrity of your users' passwords in the event of being hacked.

Oh, and we don't "encrypt" passwords, we hash them.

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • 3
    there is a lie in that article. bccrypt won't help against dictionary attack. And unsalted bccrypt is vulnerable to rainbow. – Your Common Sense Jan 02 '11 at 13:48
  • Not really. You'd need to generate a different rainbow table for each bcrypt configuration. And generating a rainbow for bcrypt is milions of times more complex than for a standard hash. – Mahmoud Al-Qudsi Jan 02 '11 at 14:18
  • 2
    Still, A rainbow table is a thing that is once done, can be used forever. So, it's weak excuse for not using salt at all. Your article author is just another loudmouth who reviles at some methods and idealize another. While the truth is in using all appropriate methods together. – Your Common Sense Jan 02 '11 at 14:41
  • No, that's not correct. You'd need to create a rainbow table *for each different site you want to attack*. Which makes the whole idea of a rainbow table useless. – Mahmoud Al-Qudsi Jan 02 '11 at 16:10
  • @Col. Shrapnel: Nowhere in that article does it say *not* to use a salt. In fact bcrypt (and phpass) uses salts and these are very important. – President James K. Polk Jan 02 '11 at 17:14
  • @GregS yup. it just says with big letters **Salts Will Not Help You** – Your Common Sense Jan 02 '11 at 23:44
  • Yes. Salts won't help you if you're not using something like bcrypt or pbkdf, etc. I don't get what's so hard to understand about this, Col Shrapnel. – Mahmoud Al-Qudsi Jan 03 '11 at 02:41
  • @Col. Shrapnel: The specification for `bcrypt` includes a salt. There is *no such thing* as "unsalted bcrypt". And it does help against an offline dictionary attack, by significantly increasing the work factor required per password test (sure, it won't help you if your password is "password" or "12345", but *nothing* will). – caf Jan 04 '11 at 04:20
  • @caf nothing will, yes. and 90% of users are using such easy passwords. That's why darn password strength is way more important than stupid hashing algorithm. – Your Common Sense Jan 04 '11 at 07:22
  • @Col. Shrapnel: Agreed, password strength is the very - but that doesn't mean that a strong algorithm is unimportant. – caf Jan 04 '11 at 07:30
  • Hi, I just found an interesting article about this topic. I think, it could be helpful: http://crackstation.net/hashing-security.htm – Krzysztof Lenda Nov 26 '12 at 22:43
2

You need to store both the hash and the salt that has been used to calculate the hash.

If you then want to check if an input is equivalent to the original input value, you can re-calculate the hash with the same salt and compare the stored hash with the new calculated one. If they are equal both input values are identical (up to some particular probability).

The choice of hashing algorithm is also important. Because there are fast hashing algorithms and rather slow hashing algorithms. And as you want to make is hard to find a collision (at least in brute-force), use a slower hashing algorithm.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
1

What generally you do is something like:

salted = HASH(password . key); // DON'T DO IT LIKE THIS 

Where key is "the salt" - the secret key stored in configuration files. So in order to crack the password you would need both the secret key and the DB so it is good to store them in separate places.

Because the schema I had shown is not strong enough, it is better to use HMAC for this purpose rather then hand written salting. Such an operation is as simple as hash and PHP supports this.

salted = hash_hmac('sha1',password,key); // <-- this is ok

See this: http://php.net/manual/en/function.sha1.php

Artyom
  • 31,019
  • 21
  • 127
  • 215
1

What I am wondering about how do you salt a hash and work with the salted hash? If the password is encrypted with a random generated salt, how can the we verify it when the user tries to authenticate? Do we need to store the generated hash in our database as well?

Yes. First you generate a salt, then generate a hash from the password plus the salt and save both hash and salt together.

Is there any specific way the salt preferably should be generated?

I doubt that there's consensus on what's preferable. I use /dev/random. e.g.

$salt = '$2a$12$' 
    . strtr(substr(base64_encode(shell_exec(
        'dd if=/dev/random bs=16 count=1 2>/dev/null'
        )), 0, 22), '+', '.')
    . '$';
$hash = crypt($input, $salt);

Which encryption method is favored to be used? From what I hear sha256 is quite alright.

See Computer Guru's answer, i.e. use bcrypt as in the example above. See the PHP manual page on crypt(). If bcrypt isn't on your system, one way to get it is the Suhosin patch.

Would it be an idea to have the hash "re-salted" when the user authenticates?

The salt just makes dictionary attacks slower. If you have a decent random salt to start with I wouldn't think changing it frequently would help. You'd probably be better off investing your effort in making users choose good passwords, changing them often enough and keeping your Blowfish cost parameter at a sensible value.

And lastly is it any major security boost to rehash it a bunch of times?

That question belongs in the world of cryptographic design. I recommend you leave that to the experts. In other words: forget it—just use best common practices.

  • Security experts advocate **you should rehash** multiple (several thousand times), this makes the computation of rainbow tables thousand of times slower. – Alix Axel Jan 02 '11 at 15:49
  • My wording was unclear, sorry. By "forget it" I didn't mean forget rehashing. I meant forget trying to answer the question yourself and follow BCPs instead. And, as you say, BCPs do recommend rehashing. But rehashing in your own code thousands of times is, iiuc, important only if you use one of the fast hash functions like MD5 or one of the SHAs. With bcrypt, the cost parameter controls how many iterations are used. In the example I gave, the cost factor is 12 and the hash takes 0.37 seconds to generate on my old iMac. –  Feb 16 '11 at 21:17
0

Three simple rules. Okay, five:

  1. Most important thing, if you want to consider your password storage being safe: allow strong passwords only e.g. at least 8 chars with some different case letters and numbers and even punctuation marks
  2. Allow users to use strong passwords only. Make a routine to check length and character range and refuse weak passwords. Even get yourself John the ripper database and check against it.
  3. Torture users wickedly, beat them up, until they choose good long and random enough passwords. Passwords! Not salt, of which everyone is delighted to talk for hours, but password itself should be random enough!
  4. Salt your passwords and store that salt along with user info. you can use user email and username as a perfect salt, no need to invent something extraordinary random.
  5. Certain algorithm is not that important, you can use MD5 as well. In real world there are very few people who would bother themselves with cracking user database of your famous Fishing And Grocery Fans Society site forums.
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • 1
    Using email as part of the salt is a little unstable since the user might change their email address. The point of salting is just that two users with the same password won't have the same hash (it defeats rainbow table attacks, or more accurately would require a separate rainbow table for each user record). A strong approach is to use a large amount of entropy (/dev/urandom if you can), store 64 bits of random data as part of the user record, and use this as the salt. The rainbow table to defeat this would be unattainably large. – MightyE Jan 02 '11 at 14:26
  • @MightyE you are probably misunderstands the rainbow table term. A "rainbow table for each user record" is called "dictionary attack" – Your Common Sense Jan 02 '11 at 14:30
  • 1
    How can a username and email address be useful as a salt? They are very predictable. – President James K. Polk Jan 02 '11 at 17:51
  • @GregS yes. So what? what is attack scenario? – Your Common Sense Jan 02 '11 at 23:45
  • Re point 3 - Your user database *is* useful to attackers even if your site itself is uninteresting, because the chances are that half of your users use the same password on gmail / facebook / other attractive site. (See, for example, the recent Gawker case, which resulted in Twitter spam from compromised accounts). – caf Jan 04 '11 at 04:26
  • @caf yeah, useful. So what? It is hashed, if you didn't notice. How it is supposed to use that database? Why none of you ever trying to think before comment? – Your Common Sense Jan 04 '11 at 07:24
  • Obviously, because if you just use a simple salt+hash, the attacker would use a dictionary attack to find most or all of the passwords. This isn't theoretical; it has happened and will happen again. It is **you** that is making unsubtantiated claims. – caf Jan 04 '11 at 07:28
  • @caf don't be stupid, read WHOLE DARN ANSWER, not only last item! Its **strong** passwords, invulnerable to dictionary attack! – Your Common Sense Jan 04 '11 at 07:32
  • @Col. Shrapnel: 8 character passwords are **not** strong enough to withstand a dictionary attack if your hash function is fast - read the page that @Computer Guru linked to in his answer again, and this time try to comprehend what it is saying. The US$2000 cluster mentioned can try *every* mixed case alpanumeric 8 character password in a touch over 3 days - and GPUs are only getting faster. – caf Jan 04 '11 at 07:39
  • @caf well you came at it at last. How long it take to make this **whole** database useful in the way you are proposing? Care to comprehend what is YOU say? – Your Common Sense Jan 04 '11 at 07:45
  • @caf and you are still messing up brute-force with dictionary attack. – Your Common Sense Jan 04 '11 at 07:47
  • @Col. Shrapnel: No, a rainbow table is a precomputed brute force or dictionary attack. It *is* possible to precompute salted hashes, but you need a rainbow table for each possible salt. That's why if you're using sufficiently unique salt it's unattainably large, especially if you use sufficient bits of entropy for your salt. This was my point: it is actually easier to brute force than rainbow at this point (that doesn't make a rainbow table suddenly become a dictionary, it just makes an attacker prefer brute force over rainbow). Also I think you're confusing dictionary and brute force. – MightyE Jan 13 '11 at 14:15