7

Possible Duplicate:
How to best store user information and user login and password
How do you use bcrypt for hashing passwords in PHP?

I am used to using the md5() which I know is now outdated and I hear that sha1() is also insecure. So what is exactly the best way to store and retrieve passwords in a database these days with security in mind? I'd be very happy if you can provide a small example.

Thank you!

Community
  • 1
  • 1
user1296953
  • 135
  • 3
  • 9
  • Have you taken a look at sha2() – Justin Sep 20 '12 at 19:23
  • [bcrypt](http://stackoverflow.com/questions/4795385/how-do-you-use-bcrypt-for-hashing-passwords-in-php) is the way to go. – tadman Sep 20 '12 at 19:24
  • 2
    Related: [How to securely hash passwords?](http://security.stackexchange.com/questions/211/how-to-securely-hash-passwords) – Brendan Long Sep 20 '12 at 19:26
  • Every time when MD5 pops up on SO, a war starts about the safety of MD5. If salted with a string of enough length I haven't seen any brute force successes – JvdBerg Sep 20 '12 at 19:28
  • @JvdBerg The salt isn't the problem. Salts exist to beat rainbow tables, and you really don't need a very big one (64 bits is more than enough). The problem is that MD5 is way too fast. Read the answers on the link I posted above. – Brendan Long Sep 20 '12 at 19:30
  • you could use AES `AES_DECRYPT(crypt_str,key_str)` `AES_ENCRYPT(str,key_str)` directly inline of your mysql queries... key storage becomes your weak point though. Do you need to decrypt or can you one way hash and match? – Dave Sep 20 '12 at 19:32
  • @BrendanLong You are referring to GPU calculations? Any real proof that it can be done? – JvdBerg Sep 20 '12 at 19:33
  • @JvdBerg GPU's aren't required, they just make the problem significantly worse. A standard CPU can test millions (or hundreds of millions) of MD5 or SHA1 hashes per second. – Brendan Long Sep 20 '12 at 19:39
  • @JvdBerg EVERY possible hashing or encryption algorithm is vulnerable to dictionary (rainbow table) attacks. It all depends on the size of the table and even if you don't find the real input, you find a collision which will work as a token to access the system. (besides.. if someone knows the hashes of all the passwords in your user table, you got bigger problems than hash security!!!) – Gung Foo Sep 20 '12 at 19:39
  • @GungFoo bcrypt, scrypt and PBKDF2 are *not* vulnerable to rainbow table attacks and never have been. Every algorithm is vulnerable to dictionary and brute-force attacks, but using a good algorithm can make them several orders of magnitude harder. – Brendan Long Sep 20 '12 at 19:54
  • a hashed md5 string of 10 chars gives (128-32)^10*32 bytes rainbow table. That are 1.9E9 Petabytes. Hmm .. need a bigger harddisk – JvdBerg Sep 20 '12 at 19:56
  • 1
    @JvdBerg - For 1.9E9 combinations you need about [0.25 seconds](http://hashcat.net/oclhashcat-lite/#performance) with a GPU in 2012. There is no need to store them on a harddisk, just try (brute force) until a match is found. – martinstoeckli Sep 20 '12 at 20:06
  • @martinstoeckli 6.6E19 combinations .. and with 10 byte utf-8 string aprox 1.3E30 combinations .. 1.3E30 comb at 10000E6 calc/sec = 4E12 years to crack .. – JvdBerg Sep 20 '12 at 20:22
  • @JvdBerg - Sorry about misreading your Petabytes, and yes you can always use long and save passwords (utf-8 with 10 _characters_ can result in 10-30bytes). The question is, do users really use such long and hard to remember passwords? And why not using Bcrypt, if it is equally easy to use as MD5? – martinstoeckli Sep 20 '12 at 20:33
  • My point is that all the horror stories about MD5 are out of context. A password + utf-8 salt with sufficient length will be save for many more years. – JvdBerg Sep 20 '12 at 20:36
  • 1
    @JvdBErg - This is a misunderstanding, the salt cannot be counted to the password length, it is **not** a secret and will be stored together with the password-hash. With an SQL-injection attack you will get this salt. – martinstoeckli Sep 20 '12 at 20:38
  • @martinstoeckli What is the point of hashing a password if the site is vulnerable to SQL Injection? $hash=MD5(salt.$password)! – JvdBerg Sep 20 '12 at 20:42
  • 1
    @JvdBerg - Actually this is the main point! It protects the passwords of your users, in case an attacker gains access to the database with the password-hashes. This passwords are usually used on other sites as well. – martinstoeckli Sep 20 '12 at 20:49
  • PHP 5.5 is going to have a rather nice API: https://gist.github.com/3707231 – sdcvvc Sep 21 '12 at 14:42

5 Answers5

9

I would recommend looking at bcrypt, since it can help against brute-force attacks. http://codahale.com/how-to-safely-store-a-password/

You can find example Here

Community
  • 1
  • 1
nKandel
  • 2,543
  • 1
  • 29
  • 47
  • 2
    bcrypt is the only method that's designed specifically to be difficult to crack. SHA1, SHA256 and especially MD5 are not sufficient. – tadman Sep 20 '12 at 19:27
  • bcrypt isn't the *only* method. There's also scrypt (uses more memory -- which is a good thing) and PBKDF2 (which is similar to bcrypt but not quite as nice). – Brendan Long Sep 20 '12 at 20:22
5

You should really use bcrypt to hash your passwords, it was designed especially for hashing password.

Hash functions for passwords should be slow (need some computing time). Most hash algorithms like SHA-1 and MD5 or even SHA-256 are designed to be fast, but this makes it an easy target for brute force attacks. An off-the-shelf GPU is able to calculate about 8 Giga MD5 hashes per second!

Don't be afraid to use bcrypt! It is not for high security sites only, and using it can be as easy, as using an md5 hash. It's recommended to use a well established library like phpass, and if you want to understand how it can be implemented, you can read this article, where i tried to explain the most important points.

UPDATE:

Current PHP versions offers the functions password_hash() and password_verify() to handle passwords. Use them like this:

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
martinstoeckli
  • 23,430
  • 6
  • 56
  • 87
  • Just in case anyone's wondering -- bcrypt isn't slow in a generally-noticeable sense (you can make it capable of hashing hundreds or thousands of passwords per second if you want). What's important is that it's not as fast as MD5 or SHA1 (which can hash hundreds of millions of passwords per second). A normal person has no need to hash hundreds of millions of passwords per second, but an attacker does. – Brendan Long Sep 20 '12 at 19:44
  • 1
    @Brendan Long - True, the difference is, that it offers a **cost factor** wich determines how many iterations of hashing are done. Increasing the cost factor by 1, doubles the needed time, and makes the algorithm adaptable for future (and therefore faster) hardware. – martinstoeckli Sep 20 '12 at 19:48
2

We use crypt with Blowfish:

// Hash our password
$hashed = crypt($plain_text_password, '$2a$08$' . substr(hash('whirlpool', microtime()), rand(0, 105), 22));

// Validate a password
if (crypt($plain_text_password, $hashed) == $hashed)) {
    // Valid password
}

The salt prefix $2a$ (read the docs) is what instructs crypt to use Blowfish. And assuming the implementation of crypt(3) in the underlying OS supports it, you get it "for free."

Sean Bright
  • 118,630
  • 17
  • 138
  • 146
  • I really don't understand what this part is doing: `. substr(hash('whirlpool', microtime()), rand(0, 105), 22)`. – Brendan Long Sep 20 '12 at 19:31
  • It's using the `whirlpool` algorithm to generate a 128 character hash value based on the current time, then pulling 22 characters out of that and appends them to the salt passed to `crypt`. – Sean Bright Sep 20 '12 at 19:35
  • The more times you call `rand()`, the more secure your application, obviously. _grin_ – Sean Bright Sep 20 '12 at 19:36
  • It seems like if all you want is a salt, it's simpler (and faster) to just grab 22 characters of random data.. – Brendan Long Sep 20 '12 at 19:43
-3

md5\sha1 + unique salt = best way

Don't be paranoid.

kguest
  • 3,804
  • 3
  • 29
  • 31
MrSil
  • 608
  • 6
  • 12
  • md5\sha1 + uniqe salt is the best than your own bicycle – MrSil Sep 20 '12 at 19:26
  • No it's not. It's way too fast and complicated. [Use bcrypt](http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html). – Brendan Long Sep 20 '12 at 19:28
  • He's asking about md5\sha1 not about other func's. I'm using bcrypt in my rails apps, and md5\sha1 in php. – MrSil Sep 20 '12 at 19:30
  • 2
    The choice of language has nothing to do with it. MD5 and SHA1 are not designed for password hashing (more specifically, they are not [key derivation functions](https://en.wikipedia.org/wiki/Key_derivation_function)). Why use insecure functions when secure ones exist? – Brendan Long Sep 20 '12 at 19:35
-5

You could look up alot of encryption codes or mix them for example like this:

sha1(md5(sha1($pw)));

I find that unnecessary so what I use is SHA512 hash("sha512",$pw);

Arturs Lapins
  • 29
  • 1
  • 1
  • 3
  • Nope. Please don't post misleading answers like this. – tadman Sep 20 '12 at 19:25
  • This isn't necessarily a bad idea, but [you should understand the implications](http://crypto.stackexchange.com/a/328/2397) before doing it. You don't automatically get better security by chaining hash functions. – Brendan Long Sep 20 '12 at 20:00