13

I'm in the process of creating a gaming community site that I'm aiming to release to the public soon. Currently, I'm working on passwords and logins. I've only used MD5 before, but I've read about password safety and heard that salting is currently the way to go.

Here's my plan: Every user has their own unique salt of 12 random characters (#/¤& etc), stored in the users table. The salt is hashed (using SHA-256) along with the password on registration, and re-hashed on login.

How does this sound to you? Anything I can improve? Should I go for SHA-512 and a longer salt, or is this enough?

Brighid McDonnell
  • 4,293
  • 4
  • 36
  • 61
Jarpi
  • 131
  • 1
  • 3

6 Answers6

17

Your suggestion of 12 bytes should be an adequate length for a salt. That would require a dictionary attack to prepare 296 databases of hashed passwords. Someday this might be a trivial operation for a cracker, but we're still a ways off from that.

SHA256 is recommended by NIST as having adequate hashing strength for passwords, at least for now.

If you want to explore even stronger methods of password security, look into key-strengthening techniques like PBKDF2, or adaptive hashing with Bcrypt. But these have no direct support in SQL. You'd have to do the hashing in application code and then post the hash digest to your database.

It may seem like security overkill for a gaming site, but it's a good practice to do it. Because many users (inadvisably) use the same password for their gaming login as they do for their banking login! You don't want to be responsible for an authentication breach that leads indirectly to major losses.

Community
  • 1
  • 1
Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • 1
    Very good advice. (Though the OP seems to be using 12 characters not 12 bytes for the salt, which is a lot less entropy). – Pete Jul 07 '10 at 05:41
  • Yes, good point. By using only printable characters, he'll use fewer than 8 bits per character. – Bill Karwin Jun 22 '11 at 22:28
  • 1
    This is bad advice. SHA256 is not good for password hashing; it is too fast. You should use bcrypt, scrypt, or PBKDF2. – D.W. Sep 17 '11 at 01:41
  • 2
    @D.W. You're right, bcrypt or PBKDF2 are stronger solutions. That's why I mentioned them in my answer. – Bill Karwin Sep 17 '11 at 05:05
6

Update:

Don't use hashing or HMAC. Use bcrypt or scrypt. See http://codahale.com/how-to-safely-store-a-password/

Original:

Don't simply hash. Use HMAC. (And avoid doing your own hashing or crypto if there is a library available, since libraries benefit from expert input.)

References:

  1. http://rdist.root.org/2009/10/29/stop-using-unsafe-keyed-hashes-use-hmac/
  2. http://us2.php.net/manual/en/function.hash-hmac.php
carbocation
  • 8,806
  • 7
  • 25
  • 30
3

It's probably sufficient for your use case.

However, it could be improved by:

  1. Increase the size of the salt

  2. The salt should be not be limited to a small subset of characters

  3. Iterate the hashing, say 1000 times (key strengthening)

Have a look at phpass.

Pete
  • 1,773
  • 8
  • 11
  • 2
    I didn't downvote you, but I don't think that hashing a hash offers any practical benefit. I've read that [hash chaining](http://en.wikipedia.org/wiki/Hash_chain) can help prevent password theft in the event that the key is sent over unsecured channels, but when the communication is between a server and its database, I kind of doubt it would help. And I honestly don't know, but I have a gut feeling that successively hashing will introduce noise to the hash that will make it easier for someone else to reproduce and exploit. Salts are probably the best way to go. – Andrew Jul 07 '10 at 04:42
  • 4
    I was referring to key strengthening, e.g. PBKDF2 (as mentioned by Bill above). Multiple iterations is considered best practice, as it hinders a brute force attack on a known hash value - where the attacker has got access to the DB and wants the password (many people reuse passwords across sites). There's no known mathematical weakness in doing so with the common hash functions. – Pete Jul 07 '10 at 04:51
  • 4
    @Col. Shrapnel The salt stops **pre**-computed dictionary attacks and hinders rainbow tables. Multiple iterations hinder brute force - the salt is known with the hash value and doesn't alone hinder brute force enough. – Pete Jul 07 '10 at 05:13
  • Having read through the research really quickly, if you lose both your DB and your salt to an attacker, key stretching will definitely help. Iterating a hashing algorithm 1000 times will force an attacker to take 1000 times longer to crack a given user's password. Adding two characters to your salt will do the same thing; *but if the salt was lost as well*, you're back to regular brute force in 1x time. However, your authentication system can now be used to DoS you. I've found no citations about weaknesses of iterating over SHA 1000x, but I fear it reduces security by increasing collisions. – Andrew Jul 07 '10 at 05:44
  • 2
    'I fear it reduces security by increasing collisions' If you can show the math to back that up, your gut will win instant kudos in the crypto community :-) – Pete Jul 07 '10 at 05:53
  • @Pete: You are exactly right. The thing that bothers me is specifically this: Let's say your original salted string is [8-or-more-byte-password] + [64-byte-salt]. It is reduced to a 32-byte (MD5) hash. Unless every 32-byte string results in a new and completely unique 32-byte string, you've introduced a new range of collisions. Do that 1000 times, that range will be at the very least the same or it may be expanded. Further, most hashing algos were written to optimize the hashing of documents of different lengths, not a thousand docs exactly 32-bytes long. I'm not a wonk. I'm just skeptical – Andrew Jul 07 '10 at 06:09
  • 1
    See http://www.schneier.com/paper-low-entropy.html if you want to read about key-stretching. – Bill Karwin Jul 07 '10 at 06:26
  • @Andrew Actually, I can understand what you mean. However: 1) Most hash functions take a fixed size input. A document will be padded and processed in n blocks - not too different to processing the password n times. (Also the password length isn't fixed). 2) The hash function produces what is in effect a 'random' output. An input of random data doesn't make the output any less random. Not enough space here to go through the math and info thoery... – Pete Jul 07 '10 at 06:27
  • Reading through PBDKF2, I see it re-salts on every iteration. This pretty much negates *everything* I said in my comment above (maybe I should just delete it). I do think that having your authentication system hang for half a second while it authenticates a user is still a bad idea though. A malicious script running on a single computer hitting your login script 5 times a second will bring things to a pretty nasty halt. – Andrew Jul 07 '10 at 06:30
  • Actually 1000 iterations is about 100ms or less on modern hardware. Obviously a good login system has brute force prevention on the front-end, which negates the DoS attack (and there's likely other parts of the site that are a better target) – Pete Jul 07 '10 at 06:34
  • @Pete Wow. I didn't quite believe you that 1000 iterations would take that long so I just tested it myself. 5000 iterations take less than 0.008 seconds (on a box with zero load). So what was my point exactly? – Andrew Jul 07 '10 at 06:44
  • Your point was that you were thinking critically about the problem and looking for weakness, which is a Good Thing. You've also learnt more about cryptographic hashes. – Pete Jul 07 '10 at 06:49
1

I've noticed a lot of confusion about how to do password hashing properly, especially on stackoverflow. And I've seen some REALLY BAD recommendations. So I've written a page that should clear everything up. There's a bit more to it than using a simple hash.

More info and source code: How to do password hashing properly

Feel free to share this link whenever someone has a question about password hashing. This is my first post on stackoverflow so sorry if I'm not doing it right

FireXware
  • 19
  • 1
  • 1
    I appreciate your work to try to write this up in detail. However, this advice doesn't fully take into account the state-of-the-art understanding in the security literature. The material on salting is good, but the material on selection of a hash algorithm is not so good. You recommend SHA256, but that's not a good choice for hashing passwords. Folks should use scrypt, bcrypt, or PBKDF2. – D.W. Sep 17 '11 at 01:43
-1

If you are really concerned, I would look at using the whirlpool hashing function instead of one of the SHA variants. Whirlpool has proven to be an incredibly strong hashing method, and has no history of collisions or any other weaknesses (that I know of, at least).

You can use whirlpool by employing the hash function of PHP. (Note, however, that hash() requires PHP 5.1.2 or greater.)

Dan D.
  • 1,117
  • 1
  • 11
  • 18
  • 1
    All hashing routines that take in variable-length strings and output fixed-length hashes have collisions. It's a mathematical certainty. The weakness of SHA1 and MD5 (and maybe others) is that it is possible to alter a single string in two ways to produce a collision. This weakness doesn't apply to password hashing (though conceivably, a user could concoct two passwords that result in the same hash). – Andrew Jul 07 '10 at 05:59
  • 1
    Of course, all hashing algorithms have the opportunity of collisions. What I meant was that it (to my knowledge) does not have a weakness in the hashing method itself that allows these collisions to occur more often than the mathematically probability of collisions. – Dan D. Jul 07 '10 at 07:41
-2

Your current approach is enough.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345