views:

11835

answers:

11

It is currently said that MD5 is partially unsafe. Taking this into consideration, I'd like to know which mechanism to use for password protection.

Is “double hashing” a password less secure than just hashing it once? Suggests that hashing multiple times may be a good idea. How to implement password protection for individual files? Suggests using salt.

I'm using PHP. I want a safe and fast password encryption system. Hashing a password a million times may be safer, but also slower. How to achieve a good balance between speed and safety? Also, I'd prefer the result to have a constant number of characters.

  1. The hashing mechanism must be available in PHP
  2. It must be safe
  3. It can use salt (in this case, are all salts equally good? Is there any way to generate good salts?)

Also, should I store two fields in the database(one using MD5 and another one using SHA, for example)? Would it make it safer or unsafer?

In case I wasn't clear enough, I want to know which hashing function(s) to use and how to pick a good salt in order to have a safe and fast password protection mechanism.

EDIT: The website shouldn't contain anything too sensitive, but still I want it to be secure.

EDIT2: Thank you all for your replies, I'm using hash("sha256",$salt.":".$password.":".$id)

Questions that didn't help: What's the difference between SHA and MD5 in PHP
Simple Password Encryption
Secure methods of storing keys, passwords for asp.net
How would you implement salted passwords in Tomcat 5.5

+4  A: 

Salt and a SHA1 is generally what I use. It's secure and if your data is compromised it will take a very long time to crack.

A random salt is your best bet including extra information such as a user name, e.g.:

"salt:password:username"

This makes rainbow tables unfeasible.

Gerald Kaszuba
Would sha1("somesalt".sha1($password)) be safe enough?
luiscubal
Sounds extra paranoid to be honest! If you salt both sha1's with extra data that would be decent.
Gerald Kaszuba
@luiscubal: If `somesalt` is user-specific, it's ok.
Piskvor
+42  A: 

This answer was written a year ago, and as I've learned more in the past year I figured that I should bring this up to date. Understand that this answer will be quite different than it was before.

It is completely impossible to store a password in complete security. Accept that. If your database is stolen then your users are at risk; it's only a matter of time and money before their password is stolen. Therefore, as programmers our job is to make it as hard as possible to recover this password.

Yes, there are crypt and bcrypt but I do not trust them. Blowfish is a cipher, and to get repeatable results from a cipher you must have a password--if there is a password it can be reversed. Blowfish was never designed to be destructive to data. It is simply slow and expensive to recover these passwords, but I'm certain that there is a way to decrypt them to an easy to crack condition.

Since I distrust crypt I use the following tricks to make it more expensive to crack stored passwords.

Key Principles

  1. Use HMAC, not a straight hash. HMACs are slower and require a key that must also be compromised, and their state cannot be saved for minor alterations to the data (IE, they must be 100% processed every time, no shortcuts).

  2. Generate a nonce for each user; this alone defeats the rainbow table. This is a random number that, depending on the range, expands how many resulting hashes there are.

  3. Generate a unique "site key" that is a 60 - 80 character code, used as the HMAC's key.

Bad Practices

  1. Emailing a password to your users.

  2. Keeping logs of the passwords entered into the login form.

  3. Storing passwords somewhere else in unencrypted form.

  4. Assuming that your site/software is too unknown to be affected.

Sample Code

In PHP the function hash_hmac is called with three arguments: the hash algorithm, the data, and the key. For this example I've used a global variable that acts as a site key, presumably a very large string unique to the installation that was stored in a configuration file.

function hash_password($password, $nonce) {
  global $site_key;
  return hash_hmac('sha512', $password . $nonce, $site_key);
}

This code requires PHP 5.1.2 or newer. Older versions can include the PECL Hash package.

Comparison Against the Old Answer

Effectively, the nonce and site key both act as salts. The site key is static, yes, but it is used as additional entropy in the hashing process. The nonce, being random, means that unless two users have the exact same nonce a full rainbow table must be generated for each. SHA-512 is a stronger hash than SHA1, and will naturally take longer to process; the database storage of the password will need to be 128 characters long.

However, my old answer has some potential problems that this new solution does not. A hash, without HMAC, follows a process that can be continued from any point: for example, a salt of "boo" has a specific has that can be continued to the full password's length without having to recalculate the salt value's hash. There is no truly effective way to work around this flaw of basic hashing. This necessitates calculating an HMAC instead of a simple hash.

Do not store the site key in your database, as the most common compromise is access to the database. With the site key in the file system it must be guessed, or the file system attacked. And always protect your usernames and passwords to both the database and file system vigorously!

As I Said Last Time...

Let users make their password as long as they like, but enforce a minimum length of 9 characters. Your hash won't grow in size if they enter a huge password, and it's no extra work to deal with. A minimum length of 9 ensures that there are 26^9 combinations for all lower case input, 52^9 for mixed case, and so on. Users hate to be forced to remember long and convoluted passwords, especially if they're elderly. But at least a 9 character long password will take a bit of time to force.

While the computational power to crack a hash doesn't exist, and this hash [my old method] is roughly as secure as they come ... none of it will guard against a weak password. For this purpose brute-force attacks will always be more effective, and so must be guarded against more strongly.

And last but not least: I am not an expert. Be as paranoid as possible, make things as hard to intrude as possible, then, if you are still worried, contact a white-hat hacker to see what they say about your code/system.

The Wicked Flea
I see. But in my case, the person may have multiple emails. Should I use the ID(BIGINT primary key) instead?
luiscubal
@luiscubal: as long as the values for your salt come from a sufficiently large space, it will be a good salt. Your ID value will probably suffice, especially if the number of records is large (the number of IDs will be large).
rmeador
you could use anything that the user only has one of, but ideally something that doesn't change.
Tom Haigh
I'd include something secret as well. The point is, you want the hash function's input to be consistent for a correct password, but you also want it to be nonguessable so someone can't brute-force guess the password offline. (vs. having to do it through your webpage which is much slower)
Jason S
a secret doesn't help as your password DB is supposed to be secret anyway - if they can get hold of that DB, they can also find whatever secret you're using. it is however important that the salt is random.
frankodwyer
note, it's not really true that 'the computational power to decrypt' doesn't exist yet. since most passwords are dictionary words or dictionary derived, a dictionary based attack is usually very effective (hence the use of password policies and iteration counts).
frankodwyer
Frank, while what you say is true, the algorithmic cycles it takes to generate the words doesn't make it feasible. Don't forget the inclusion of the salt. Brute force will always work if they know your hash algorithm and salt, otherwise it's _virtually_ impossible.
The Wicked Flea
But that doesn't make insecure passwords any safer. It just makes the database rows safer if compromised, at which point you should change your salt immediately and inform your users to change their passwords.
The Wicked Flea
Even when the salt and algorithm are known, finding a password by brute-force search will take many years if the proper method is used. Passwords are cracked when they are predicted by following a pattern, such as transforming dictionary words and incorporating other cribs. An essential part of the method is some sort of computationally intensive key stretching technique, like using thousands of iterations of the hash function.
erickson
for the accepted answer, there is a lot of advice that is in contradiction to most of the arguments on posts like: http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/I'm not slamming the wicked flea - just expressing a growing "hair-pulling" feeling regarding trying make sense of this. crypto-security seems a lot like a poetry slam. everyone has their own beat and groove.
42
42, if I were designing a truly secure system, I'd suggest a military grade hash algorithm anyway with a ~16bit randomly generated number stored in the database. In general use, a salt with a password is better than none--unless either is compromised. I'm not claiming to be an expert, nothing is better than enforced password rotation plus a military-grade algorithm, but for basic non-critical software this is enough.
The Wicked Flea
@wicked flea, I'm not arguing with you. Just pointing out how convoluted and complex this area of our work is. I keep hoping to get schooled by the be-all, end-all smartest, best practice for setting up a small web site's content management system. I'm still learning here. ...every time I read something that makes sense, I soon notice 5 other posts that contradict it. that round-and-round gets dizzying quickly :)
42
Absolutely! I've just shared what I've found. I found a number of things from Shneier on Security and a very long (convoluted) discussion on a news site (don't remember which now).
The Wicked Flea
*"Even MD5 is still safe, as aside from a brute-force attack the computational power needed to decrypt doesn't exist yet."* OMG, I don't believe it. MD5 can't be "decrypted", period. But it is definitly *not* safe, as it is. **Ever heard of rainbow tables?**
Lo'oris
Look, if you're using MD5 on software that requires high security (like a store) then YOU'RE the fool, not me. I know that MD5 is extremely fast, but if you're designing forum software with good practices it's still generally secure.
The Wicked Flea
Interesting revision. Is the user ID(say, an auto increment BIGINT) a good nonce? Or since it's not random it isn't good? Also, I'll have to store the nonce for each user in the database... Does the site key + nonce + HMAC provide significant improved security over a salted(with user ID) hash iterated multiple times? Similarly, is iterating HMAC multiple times good for security?
luiscubal
+5  A: 

I wouldn't store the password hashed in two different ways - your system is then at least as weak as the weakest of the hash algorithms you are using.

Tom Haigh
not for password hashing. the attacker only needs to break one hash to retrieve the password. the point is moot anyway as neither MD5 nor SHA1 have any practical breaks available in the password scenario.
frankodwyer
sorry, i misread your answer as recommending using two hashes...you are in fact correct. Using two hashes weakens the system in the password case, as they only need to break the weaker hash.
frankodwyer
A: 

I usually use SHA1 and salt with the user ID (or some other user-specific piece of information), and sometimes I additionally use a constant salt (so I have 2 parts to the salt).

SHA1 is now also considered somewhat compromised, but to a far lesser degree than MD5. By using a salt (any salt), you're preventing the use of a generic rainbow table to attack your hashes (some people have even had success using Google as a sort of rainbow table by searching for the hash). An attacker could conceivably generate a rainbow table using your salt, so that's why you should include a user-specific salt. That way, they will have to generate a rainbow table for each and every record in your system, not just one for your entire system! With that type of salting, even MD5 is decently secure.

rmeador
+1 for the link to "rainbow table"
Jason S
constant salt is not a great idea...probably not a fatal flaw but it unnecessarily weakens the scheme.
frankodwyer
+2  A: 

Google says SHA256 is available to PHP.

You should definitely use a salt. I'd recommend using random bytes (and not restrict yourself to characters and numbers). As usually, the longer you choose, the safer, slower it gets. 64 bytes ought to be fine, i guess.

Alex Ati
+2  A: 

SHA1 and a salt should suffice (depending, naturally, on whether you are coding something for Fort Knox or a login system for your shopping list) for the foreseeable future. If SHA1 isn't good enough for you, use SHA256.

The idea of a salt is to throw the hashing results off balance, so to say. It is known, for example, that the MD5-hash of an empty string is d41d8cd98f00b204e9800998ecf8427e. So, if someone with good enough a memory would see that hash and know that it's the hash of an empty string. But if the string is salted (say, with the string "MY_PERSONAL_SALT"), the hash for the 'empty string' (i.e. "MY_PERSONAL_SALT") becomes aeac2612626724592271634fb14d3ea6, hence non-obvious to backtrace. What I'm trying to say, that it's better to use any salt, than not to. Therefore, it's not too much of an importance to know which salt to use.

There are actually websites that do just this - you can feed it a (md5) hash, and it spits out a known plaintext that generates that particular hash. If you would get access to a database that stores plain md5-hashes, it would be trivial for you to enter the hash for the admin to such a service, and log in. But, if the passwords were salted, such a service would become ineffective.

Also, double-hashing is generally regarded as bad method, because it diminishes the result space. All popular hashes are fixed-length. Thus, you can have only a finite values of this fixed length, and the results become less varied. This could be regarded as another form of salting, but I wouldn't recommend it.

Henrik Paul
The target site shouldn't contain anything too sensitive(it's not a bank), but still I'd rather have it secured.
luiscubal
double hashing does not reduce the result space. iterative hashing is a common control against dictionary and brute force attacks (it slows them down much more than it slows down your password checking).
frankodwyer
+1  A: 

A salt and hash (SHA1) is probably OK. However I generally also store an iteration count with this. So the algorithm is (pseudocode):

iterations=random(1..max_iterations)
salt = random(saltbits)
hash=password
for (iterations)
   hash=SHA1(hash+salt)

then store salt, iterations and the hash (plus it's a good idea to store an identifier of the hash function - say 0 = SHA1. This allows the hash function to be replaced in future.)

With this scheme you can configure to use just 1 iteration or a random number up to as many as you want.

frankodwyer
+2  A: 

In the end, double-hashing, mathematically, provides no benefit. In practice, however, it is useful for preventing rainbow table-based attacks. In other words, it is of no more benefit than hashing with a salt, which takes far less processor time in your application or on your server.

Max
multiple hashing also protects against dictionary and brute force attacks - i.e. it simply makes them take longer to compute.
frankodwyer
double hashing won't give you a significant advantage but multi round hashing iterations are still a feasible defense against dictionary and bruce force attacks. Industrial strength password hashes use 1000+ rounds. PKCS#5's PBKDF1 suggests 1000 rounds minimum.
Berk D. Demir
A: 

Though the question has been answered, I just want to reiterate that salts used for hashing should be random and not like email address as suggested in first answer.

More explanation is available at- http://www.pivotalsecurity.com/blog/?p=84

"Recently I had a discussion whether password hashes salted with random bits are more secure than the one salted with guessable or known salts. Let’s see: If the system storing password is compromised as well as the system which stores the random salt, the attacker will have access to hash as well as salt, so whether the salt is random or not, doesn’t matter. The attacker will can generate pre-computed rainbow tables to crack the hash. Here comes the interesting part- it is not so trivial to generate pre-computed tables. Let us take example of WPA security model. Your WPA password is actually never sent to Wireless Access Point. Instead, it is hashed with your SSID (the network name- like Linksys, Dlink etc). A very good explanation of how this works is here. In order to retrieve password from hash, you will need to know the password as well as salt (network name). Church of Wifi has already pre-computed hash tables which has top 1000 SSIDs and about 1 million passwords. The size is of all tables is about 40 GB. As you can read on their site, someone used 15 FGPA arrays for 3 days to generate these tables. Assuming victim is using the SSID as “a387csf3″ and password as “123456″, will it be cracked by those tables? No! .. it cannot. Even if the password is weak, the tables don’t have hashes for SSID a387csf3. This is the beauty of having random salt. It will deter crackers who thrive upon pre-computed tables. Can it stop a determined hacker? Probably not. But using random salts does provide additional layer of defense. While we are on this topic, let us discuss additional advantage of storing random salts on a separate system. Scenario #1 : Password hashes are stored on system X and salt values used for hashing are stored on system Y. These salt values are guessable or known (e.g. username) Scenario#2 : Password hashes are stored on system X and salt values used for hashing are stored on system Y. These salt values are random. In case system X has been compromised, as you can guess, there is a huge advantage of using random salt on a separate system (Scenario #2) . The attacker will need to guess addition values to be able to crack hashes. If a 32 bit salt is used, 2^32= 4,294,967,296 (about 4.2 billion) iterations will can be required for each password guessed."

Gaurav Kumar
Even if the attacker gets the salt, a "sitesalt:usersalt:password" string is still resistant to precomputed tables, since the attacker needs to generate the tables for every user(so the attack becomes far slower), unless of course a specific user is being targeted...
luiscubal
Regarding "Even if the attacker gets the salt, a "sitesalt:usersalt:password" string is still resistant to precomputed tables" , Totally agree. My point is that sitesalt if made random and long, will make system more secure than it (sitesalt) being predictable. I've seen some people recommending use of email id etc as salt, and I discourage that.
Gaurav Kumar
A: 

I still have a question regarding the security of a salted password. If someone gets access to my db (which would usually happen if you prevent injections and stuff like that) the attacker has the salt and passwort hash. Now i often read here that with a salt, he needs to create rainbow tables himself for every salt and check it, but imo thats not true. There are many password cracking programms nowadays that simply have a field for the salt and the password hash. While that programm still has to create a rainbow table based on the salt your provide, its still doing it on the fly and it will only take a bit longer, but overall there is not much more security than to just sha1() or md5() something.

BarthQuay
The attacker needs to have both the SALT and the DATABASE. Since the salt wouldn't normally be stored in the database, that makes the attack significantly harder. Also, if the salt is different for each user, the precomputed table(for common passwords) no longer works, making the attack longer to execute. But of course, with the database, the attacker has a LOT of time, but the cracked website also gets more time to react.
luiscubal
A: 

I must have a high level of paranoia to encrypt a password I use multiple systems. This is the first stage of the password encryption.

sha1(interleave(md5($password, SITE_SECRET_PASSWORD_SALT), md5($password, SITE_SECRET_PASSWORD_SALT_2)))

Both site secrets are stored in separate locations, one as an actual site secret and the other a server secret. Both stored outside the root of the system and only loadable by the php scripts. I accept that if someone gets root access to the system there is little protection that is going to slow them down.

Edit: Forgot to add that I only use md5 to get similar length strings for the interleave.

Khainestar