6

I'm reading so much conflicting advice as to how to store passwords securely. All I know for sure is not to use MD5! I've seen people advocate using PHP's bcrypt function, which seems like it'd hog the server's processor. I've seen advocates for salts, and advocates for not using salts.

It's all just so unclear. Is there real and credible advice as to how to store passwords securely?

Edit: After a fair amount of research, I found an article from ;login: that deals with the topic in quite some depth: http://www.usenix.org/publications/login/2004-06/pdfs/alexander.pdf

Matty
  • 33,203
  • 13
  • 65
  • 93
  • It's all based on opinion. I use just use MD5. Suits my needs. – Steve Robbins Jul 29 '11 at 22:35
  • The real solution? Don't store passwords. Use OpenID providers. :-) – corsiKa Jul 29 '11 at 22:41
  • @imoda MD5 has known weaknesses – Matty Jul 29 '11 at 22:43
  • @TotalFrickinRockstarFromMars (Thanks for making me type that!) An external provider isn't suitable in this case unfortunately. – Matty Jul 29 '11 at 22:43
  • 1
    possible duplicate of [Help me make my password storage safe](http://stackoverflow.com/questions/1581610/help-me-make-my-password-storage-safe) – mercator Jul 29 '11 at 22:57
  • @mercantor Not really - I'm looking more for research-backed answers to sort through the confusion and conflicting advice, which is why this differs. – Matty Jul 29 '11 at 23:00
  • possible duplicate of [(PHP) SHA1 vs md5 vs SHA256: which to use for a PHP login?](http://stackoverflow.com/questions/2235158/php-sha1-vs-md5-vs-sha256-which-to-use-for-a-php-login) –  Jul 29 '11 at 23:15
  • @pst Not a duplicate of that at all – Matty Jul 29 '11 at 23:21
  • @Matty, and yet you accepted an answer that does not provide any research, from a person who does not appear to have any authority on the subject (no offense). I can't see anything really wrong with his answer, but for the next person with the same question this will simply be *yet another* piece of conflicting advice. – mercator Jul 30 '11 at 14:22
  • @mercator If you feel you have something to contribute, please write a more complete answer and I'll not only upvote it, but change the accepted answer to yours. – Matty Jul 30 '11 at 14:29
  • I'd rather link to some earlier good answers on the subject than add my own non-authoritative, non-research-backed, conflicting 2 cents: http://stackoverflow.com/questions/401656/secure-hash-and-salt-for-php-passwords, http://stackoverflow.com/questions/116684/what-algorithm-should-i-use-to-hash-passwords-into-my-database – mercator Jul 30 '11 at 14:55
  • @mercator The answers to those questions are conflicting and exactly why I asked this question - not for more conflict. – Matty Jul 30 '11 at 15:15
  • Does anyone REALLY advocate not using a salt? I'd love to see a reference to THAT! – Troy Hunt Jul 31 '11 at 08:57
  • @Troy Hunt Yes, I read an answer on SO that said that salts weren't necessary if you were just using MD5 or something! – Matty Jul 31 '11 at 12:09

5 Answers5

6

Well, there is several parts to this.

  1. You need to try to make it difficult to get to your db and passwords in the first place, keep them secure. This includes not making your passwords cleartext and not using a symmetric encryption algorithm.
  2. You need to use a salt. Doing this prevents people from using a precomputed lookup table (i.e. rainbow table) or something like http://md5.rednoize.com/. Pick some data for your salt that is both unique and unpredictable. I usually use a random 32 bit value, but I wouldn't go much less.
  3. Some algorithms are stronger than others. This is defined in a couple ways
    1. How fast it can be computed. Longer is better. The faster the attacker can calculate hashes, the better the odds are for a bruteforce attack.
    2. If the algorithm has no known weakness which reduce the search space. For example, the number of bits in an md5 hash is misleading because there are known attacks that reduce the actual search space

As of today I think SHA1 or SHA2 with a salt is reasonably secure for the near future. There is a utility called bcrypt which uses an asymmetric variant of blowfish and has the concepts of salt and computational expense built-in, it might be worth checking out.


Edit: I wanted to clarify what a salt is, as there is a lot of misconception about it on SO and online.

What a Salt is not

A secret, pre-agreed upon string that you hash with the password. This is a secret key, not a salt.

What a Salt is

You include the salt (unique and unpredictable per hash) along with your password when hashing, but you also include a unencrypted copy of it outside of your hash, so that when verifying the hash later you are able to include the same salt when given a test password before hashing it so you can properly compare the hash.

Josh
  • 6,155
  • 2
  • 22
  • 26
  • What makes a good salt value? Also, in a nutshell, what is the difference between the SHA algorithms? What makes one preferable over the other? – Matty Jul 29 '11 at 22:52
  • Good general explanation. However you go on to suggest SHA1/2, which are *not* designed to be computationally expensive (compare to `bycrpt` or multiple rounds) -- this is counter to 3.1 above. –  Jul 29 '11 at 22:56
  • 1
    A good salt is both _unique_ and _unpredictable_. So, in a nutshell, a good salt is a random number with sufficient entropy (essentially length). What is sufficient? Up to you, I usually pick a random 32bit number as a salt. I don't honestly know enough of the math to tell you the difference specifically between SHA1 and SHA2, I'll defer to the other experts on here, hopefully they can help me improve my answer. Perhaps post that question to http://math.stackexchange.com/... or maybe I will :) – Josh Jul 29 '11 at 22:58
  • @pst Using `bcrypt` - wouldn't this be a performance drag if my application was used by many people in the same shared hosting environment? Not premature optimization, but I just don't want to deliberately build in slow code if there are equal alternatives. – Matty Jul 29 '11 at 23:02
  • @pst what would you recommend? I have used multiple rounds of sha in the past, although perhaps I should mention that. Also, I do think it really depends on the application. A properly salted SHA2 hash... I don't see that as weak. – Josh Jul 29 '11 at 23:02
  • @Josh - I'm afraid of the math stackexchange site! Last time I asked a question there, I wish I didn't, so be my guest! It's almost an obvious question, but should the salt be random every time a password is hashed, or can the same salt be used application-wide (different for each installation)? – Matty Jul 29 '11 at 23:04
  • @Matty Oh definitely change it per hash. If you use the same hash application wide, your attacker could generate a rainbow table for your site. The purpose of a salt it to make the attacker go through an expensive brute force search per-password. – Josh Jul 29 '11 at 23:08
  • @Josh This is an open source web app I'm creating, so I can't protect the source code internals. I'd have thought that if the salt were based on something like the username, the salt would become practically meaningless. How would you create the salt in this case if it has to be unique per hash? – Matty Jul 29 '11 at 23:10
  • @Matty No, it should not be based on the username - that would make it `predictable`. The fact your application is open source makes it more secure. The security should be in your key - if you think your application is more secure because the source is not visible you are making a grave mistake. Google _security through obscurity_, there is a ton of literature on that subject. – Josh Jul 29 '11 at 23:16
  • @Josh So should it just be a random string of sufficient length generated at install? The salt has to be reproducible every time, right? – Matty Jul 29 '11 at 23:17
  • @pst Thanks for the tip - I was not aware of bcrypt - very cool, I hope you don't mind I added it to my answer - hopefully this serves as credit due to you :) – Josh Jul 29 '11 at 23:18
  • @Matty let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/1972/discussion-between-josh-and-matty) – Josh Jul 29 '11 at 23:21
  • @Matty Some good questions/answers related to salts: http://stackoverflow.com/questions/536584/non-random-salt-for-password-hashes, http://stackoverflow.com/questions/1645161/salt-generation-and-open-source-software – mercator Jul 30 '11 at 14:27
3

The point of bycrpt is to hog the processor! (Relatively speaking.) It is for this reason that it is "better" for password hashing than SHA1/2. (This "better" assumes that the password hashes are already in the hands of the attacker or otherwise exposed; while it would nice if it were not the case, even big corporations have had security compromises.)

This requirement was explicitly considered for bcrypt -- if you can only process 1k hashes a second (still, that's a good bit of log-in attempts), how long will that take an attacker to brute-force? A good bit longer than if they could process 10 million hashes a second! The target attack space of a brute-force that is only of the allowed password input, which is often much smaller -- esp. in practice with "simple passwords" -- than the space of the hash!

And a salt is very much required to avoid rainbow tables which trade time for space :) A rainbow table would effectively need to be created for each unique salt value. (Thus, the more unique salt values, the more space is required and with enough values this becomes impractical for an attacker.)

Happy coding.

  • I understand the utility of bcrypt, and could justify it readily for a desktop app. However, the web app I'm creating is one that would conceivably be used by many different customers on the same shared server. Excessive processor utilization tends to make hosts cranky. Exactly *how* intensive is it? Does it have a utility in the kind of app I'm writing? – Matty Jul 29 '11 at 23:07
  • @Matty I am not aware of PHP's implementation/wrapper, but `bcrypt` is designed to "grow" with performance. It can be configured for a certain `cost`, where the number of rounds is `6^cost`. As far as how it will run on a certain server/load requires testing. In the grand scheme of things, hashing passwords is a *cheap and infrequent operation* in most cases -- there are so many other things which will be the bottleneck first. –  Jul 29 '11 at 23:10
  • In this case I might have to shy away from `bcrypt` :-( – Matty Jul 29 '11 at 23:12
  • @Matty Why? Have you run a performance analysis to say "it's too slow"? The *total cost* of an operation is *cost * count*. For a very small *count*, any reasonably small *cost* is marginalized away. –  Jul 29 '11 at 23:13
  • @Matty ... *there will be other problems first* :) Like, you know, *running PHP*. This is premature optimization in a very bad way. –  Jul 29 '11 at 23:17
2

First of all you need to use a good hash function, I suggest SHA-256. You can create a SHA-256 hash like this:

$hash = hash('sha256', $password);

In addition you could also use salting like this:

$salt = 'salt here';
$hash = hash('sha256', $salt . $password);

Moreover, you can use HMACs, like this:

$secret = 'your secret';
$hmac = hash_hmac('sha256', $password, $secret);

The best way to create solid hashes is through salting and iteration. You should loop the above functions until hashing takes 200ms.

You could also go ahead and use encryption, but that would be a bit overkill for most situations.

Chris Smith
  • 764
  • 1
  • 9
  • 22
  • 1
    You can use [GRC](https://www.grc.com/passwords.htm) to get a salt value. Random ASCII characters will do to keep it simple, any length above 32 bytes will do for SHA-256. – Chris Smith Jul 29 '11 at 22:54
  • Why would SHA-256 be good for hashing passwords? It is designed to be *fast*. This is *not desired* for hashing passwords as it is not significantly computationally expensive. Compare with `bcrypt`. –  Jul 29 '11 at 22:55
  • bcrypt is another great option, however with salting and iterations you can achieve equally good results with SHA-256. Obviously both bcrypt and sha-256 are useless if you're designing a nuclear plant, but for a casual website they are more than sufficient. – Chris Smith Jul 29 '11 at 23:04
  • So why suggest *not* using `bcrypt` and potentially introducing more issues? Security is hard to get right. `bcrypt` was designed by two *really smart* people. –  Jul 29 '11 at 23:16
  • I'm not suggesting not using bcrypt, bcrypt is great, I admit that and it is another viable option. However for a small project both bcrypt and sha2 will do good enough. bcrypt itself has several disadvantages, e.g cryptanalytic methods for ciphers are better developed than those for hash functions. – Chris Smith Jul 29 '11 at 23:23
0

This is similar to this question: Methods for storing login information in database

Credible advice: Never store your passwords in clear text!

Beyond that you have some choices to make. As I mentioned in the response to the linked question, there are two camps: let some else store your authentication data or do it your self. If you decide to do it your self, then you need to come up with a hashing routine. This should probably include a salting your passwords.

Community
  • 1
  • 1
rcravens
  • 8,320
  • 2
  • 33
  • 26
0

You can use sha256. A good thing to do is to add extra information to the password such as username, userid, or some other data to it. This way, if someone hack your database, it will be impossible to use an existant hash database to find the password. They will have to crack the password starting from zero.

darkzangel
  • 939
  • 9
  • 17
  • This is an open source application, so if someone got hold of the database tables, they'd also have access to the source code and would know how the salt is computed. This, I believe, would make the salt pointless. – Matty Jul 29 '11 at 22:53
  • Why would SHA-256 be good for hashing passwords? It is designed to be *fast*. This is *not desired* for hashing passwords as it is not designed to be computationally expensive. Compare with `bcrypt`. –  Jul 29 '11 at 22:56
  • Given that, you will need a separate chip on your computer thgat will hold your hashing algo. If you designing a bank website, then it's good idea, but for the normal web dev, it's impossible.also, if the hacked have access to an another database, it will be easy to find the password – darkzangel Jul 29 '11 at 22:57
  • Salt is still useful even when it is open source. Hashing is kind of lossy, and different text can have same hash. That means there are more than one password you can use to enter the system, and with something like rainbow table it is easy to know other passwords if your hash is unsalted. – tia Jul 29 '11 at 23:02
  • Sha256 or bcrypt, it's not rally important. Cracking the hashing algorigthm is usually not part of the problem. The problem is if a similar database containing the same password has, they could hack using a dictionnary hash database – darkzangel Jul 29 '11 at 23:04
  • 1
    See http://stackoverflow.com/questions/2235158/php-sha1-vs-md5-vs-sha256-which-to-use-for-a-php-login –  Jul 29 '11 at 23:15