44

Yes I know storing passwords in plain text is not advised.Is there a best and easy way to store passwords so that the application remains secure ??

Jeyaganesh
  • 1,334
  • 5
  • 26
  • 48
  • 2
    I would have thought that this is pretty much the same as [this question](http://stackoverflow.com/questions/1054022/best-way-to-store-password-in-database?rq=1). – lonesomeday Feb 10 '13 at 13:35
  • https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet – Quentin Feb 10 '13 at 13:36
  • http://php.net/manual/en/faq.passwords.php – Quentin Feb 10 '13 at 13:37
  • 1
    Use cryptographic hash function to hash the password and store it. Use SHA-2 or SHA-3. MD5 can still be used, but I recommend to move on to the other 2 as suggested. – nhahtdh Feb 10 '13 at 13:37
  • Use **bcrypt**, a state-of-the-art hashing algorithm designed especially for passwords. [This answer](http://stackoverflow.com/a/13153865/664108) to a related question shows an easy way to implement it. – Fabian Schmengler Feb 10 '13 at 13:42
  • Related: http://security.stackexchange.com/questions/23116/md5-collision-attacks-are-they-relevant-in-password-hashing – nhahtdh Feb 10 '13 at 13:50

6 Answers6

50

First off, md5 and sha1 have been proven to be vulnerable to collision attacks and can be rainbow tabled easily (when they see if you hash is the same in their database of common passwords).

There are currently two things that are secure enough for passwords that you can use.

The first is sha512. sha512 is a sub-version of SHA2. SHA2 has not yet been proven to be vulnerable to collision attacks and sha512 will generate a 512-bit hash. Here is an example of how to use sha512:

<?php
hash('sha512',$password);

The other option is called bcrypt. bcrypt is famous for its secure hashes. It's probably the most secure one out there and most customizable one too.

Before you want to start using bcrypt you need to check if your sever has it enabled, Enter this code:

<?php
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
    echo "CRYPT_BLOWFISH is enabled!";
}else {
echo "CRYPT_BLOWFISH is not available";
}

If it returns that it is enabled then the next step is easy, All you need to do to bcrypt a password is (note: for more customizability you need to see this How do you use bcrypt for hashing passwords in PHP?):

crypt($password, $salt);

A salt is usually a random string that you add at the end of all your passwords when you hash them. Using a salt means if someone gets your database, they can not check the hashes for common passwords. Checking the database is called using a rainbow table. You should always use a salt when hashing!

Here are my proofs for the SHA1 and MD5 collision attack vulnerabilities:
http://www.schneier.com/blog/archives/2012/10/when_will_we_se.html, http://eprint.iacr.org/2010/413.pdf,
http://people.csail.mit.edu/yiqun/SHA1AttackProceedingVersion.pdf,
http://conf.isi.qut.edu.au/auscert/proceedings/2006/gauravaram06collision.pdf and
Understanding sha-1 collision weakness

BSMP
  • 4,596
  • 8
  • 33
  • 44
C1D
  • 3,034
  • 2
  • 21
  • 20
  • Collision attack means finding 2 input with same hash (and subject to birthday paradox). Does it has any relation to this? (Since it is more of a preimage attack to the attacker - when they got a dump of the database). – nhahtdh Feb 10 '13 at 13:45
  • 4
    crypt function is encrypting upto 8 characters only. encrypting helloworld and helloworldearth returns same output. – Jeyaganesh Sep 30 '15 at 12:53
3

Hashing algorithms such as sha1 and md5 are not suitable for password storing. They are designed to be very efficient. This means that brute forcing is very fast. Even if a hacker obtains a copy of your hashed passwords, it is pretty fast to brute force it. If you use a salt, it makes rainbow tables less effective, but does nothing against brute force. Using a slower algorithm makes brute force ineffective. For instance, the bcrypt algorithm can be made as slow as you wish (just change the work factor), and it uses salts internally to protect against rainbow tables. I would go with such an approach or similar (e.g. scrypt or PBKDF2) if I were you.

ba0708
  • 10,180
  • 13
  • 67
  • 99
  • 1
    Correct me if I'm wrong, but SHA1 and MD5 are broken in term of collision-prevention (find 2 input to hash function that produces the same hash), but is still OK against pre-image attack (given a hash find some input that hash to the give value). I don't think there is any concern about using SHA1 or MD5 as long as we salt the password properly. – nhahtdh Feb 10 '13 at 13:42
  • I am no security expert, so I could also be wrong: SHA1 and MD5 are very fast and thus makes brute forcing very fast - even if you are using a salt. It is true that using a salt is a great idea because it protects against rainbow tables, but with regards to brute forcing, it is still vulnerable. When using a slower algorithm, brute forcing is just not feasible because it takes too long time to crack a password. – ba0708 Feb 10 '13 at 13:46
  • You may be correct about it being faster to compute, but I still have some doubt about how slow it is to compute the latest crypto has algo compared to MD5/SHA1. – nhahtdh Feb 10 '13 at 13:54
  • Well, if you have doubts, why not read the papers and evaluate them for yourself? https://www.tarsnap.com/scrypt/scrypt.pdf‎ https://github.com/DomBlack/php-scrypt - a PHP implementation of scrypt – Scott Arciszewski Feb 19 '14 at 14:21
2

Passwords in the database should be stored encrypted. One way encryption (hashing) is recommended, such as SHA2, SHA2, WHIRLPOOL, bcrypt DELETED: MD5 or SHA1. (those are older, vulnerable

In addition to that you can use additional per-user generated random string - 'salt':

$salt = MD5($this->createSalt());

$Password = SHA2($postData['Password'] . $salt);

createSalt() in this case is a function that generates a string from random characters.

EDIT: or if you want more security, you can even add 2 salts: $salt1 . $pass . $salt2

Another security measure you can take is user inactivation: after 5 (or any other number) incorrect login attempts user is blocked for x minutes (15 mins lets say). It should minimize success of brute force attacks.

Ahmad
  • 69,608
  • 17
  • 111
  • 137
  • You should **really** use `bcrypt` - it is not good to use cryptographic hashes that can be calculated 6 billion times a second on modern gfx cards for password storage. – Callum Rogers Feb 10 '13 at 13:57
  • "if you want more security, you can even add 2 salts: $salt1 . $pass . $salt2" It does not hurt, but there is no security gain in adding more salts. Of course the salt length should not be *too* small, but the 128 bit of md5 are enough in this case ([see also this question](http://stackoverflow.com/questions/184112/what-is-the-optimal-length-for-user-password-salt)) – Fabian Schmengler Feb 10 '13 at 14:15
  • Yes, but its more like with passwords - if you have 1 capital letter in your password, it is better to have it in a middle of the password, not as first/last character (same with the numbers or any other special chars). – Evaldas Dzimanavicius Feb 10 '13 at 14:29
2

Store a unique salt for the user (generated from username + email for example), and store a password. On login, get the salt from database and hash salt + password.
Use bcrypt to hash the passwords.

William N
  • 432
  • 4
  • 12
1

best to use crypt for password storing in DB

example code :

$crypted_pass = crypt($password);

//$pass_from_login is the user entered password
//$crypted_pass is the encryption
if(crypt($pass_from_login,$crypted_pass)) == $crypted_pass)
{
   echo("hello user!")
}

documentation :

http://www.php.net/manual/en/function.crypt.php

Nimrod007
  • 9,825
  • 8
  • 48
  • 71
0

You should use one way encryption (which is a way to encrypt a value so that is very hard to revers it). I'm not familiar with MySQL, but a quick search shows that it has a password() function that does exactly this kind of encryption. In the DB you will store the encrypted value and when the user wants to authenticate you take the password he provided, you encrypt it using the same algorithm/function and then you check that the value is the same with the password stored in the database for that user. This assumes that the communication between the browser and your server is secure, namely that you use https.

Bogdan
  • 934
  • 7
  • 13
  • 1
    No, the MySQL `PASSWORD()` function is only used for internal purposes and should not be relied upon. There are hash functions in MySQL but it is a **bad idea** to do the hashing in SQL. Passwords could easily be exposed through query logs. – Fabian Schmengler Feb 10 '13 at 13:46