Friday, May 25, 2012

Secure hash and salt for PHP passwords


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


Source: Tips4all

12 comments:

  1. TL;DR

    Don'ts


    Don't limit what characters users can enter for passwords. Only idiots do this.
    Don't limit the length of a password. If your users want a sentence with supercalifragilisticexpialidocious in it, don't prevent them from using it.
    Never store your user's password in plain-text.
    Never email a password to your user except when they have lost theirs, and you sent a temporary one.
    Never, ever log passwords in any manner.


    Do's


    Use scrypt when you can; bcrypt if you cannot.
    Use PBKDF2 if you cannot use either bcrypt or scrypt.
    Reset everyone's passwords when the database is compromised.


    Why hash passwords anyway?

    The objective behind hashing passwords is simple: preventing malicious access to user accounts by compromising the database. So the goal of password hashing is to deter a hacker or cracker by costing them too much time or money to calculate the plain-text passwords. And time/cost are the best deterrents in your arsenal.

    Another reason that you want a good, robust hash on a user accounts is to give you enough time to change all the passwords in the system. If your database is compromised you will need enough time to at least lock the system down, if not change every password in the database.

    Best practices

    Bcrypt and scrypt are the current best practices. Scrypt will be better than bcrypt in time, but it hasn't seen adoption as a standard by Linux/Unix or by webservers. If you are working with Ruby there is an scrypt gem that will help you out.

    I highly suggest reading the documentation for the crypt function if you want to roll your own use of bcrypt, or finding yourself a good wrapper or use something like PHPASS for a more legacy implementation. I recommend a minimum of 12 rounds of bcrypt, if not 15 to 18.

    I changed my mind about using bcrypt when I learned that bcrypt only uses blowfish's key schedule, with a variable cost mechanism. The latter lets you increase the cost to brute-force a password by increasing blowfish's already expensive key schedule.

    Average practices

    I almost can't imagine this situation anymore. PHPASS supports PHP 3.0.18 through 5.3, so it is usable on almost every installation imaginable—and should be if you don't know for certain that your environment supports bcrypt.

    But suppose that you cannot use bcrypt or PHPASS at all. What then?

    Try an implementation of PDKBF2 with the minimum number of rounds that your environment/application/user-perception can tolerate. The lowest number I'd recommend is 1000 rounds.

    As I Said Last Time...

    The computational power required to actually crack a hashed password doesn't exist. The only way for computers to "crack" a password is to recreate it and simulate the hashing algorithm used to secure it. The speed of the hash is linearly related to its ability to be brute-forced. Worse still, most hash algorithms can be easily parallelized to be reproduced even faster. This is why costly schemes like bcrypt and scrypt are so important.

    You cannot possibly foresee all threats or avenues of attack, and so you must make your best effort to protect your users up front. If you do not, then you might even miss the fact that you were attacked until it's too late... and you're liable. To avoid that situation, act paranoid to begin with. Attack your own software (internally) and attempt to steal log in information, or access other user's accounts. If you don't you cannot blame anyone but yourself.

    Lastly: I am not a cryptographer. Whatever I've said is my opinion, but I happen to think it's based on good ol' common sense ... and lots of reading. Remember, be as paranoid as possible, make things as hard to intrude as possible, and then, if you are still worried, contact a white-hat hacker or cryptographer to see what they say about your code/system.

    ReplyDelete
  2. 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.

    ReplyDelete
  3. A much shorter and safer answer - don't write your own password mechanism at all, use one that is tried and tested, and incorporated into WordPress, Drupal etc, i.e. Openwall's phpass.

    Most programmers just don't have the expertise to write crypto related code safely without introducing vulnerabilities.

    See this excellent answer for more about why phpass is the best way to go.

    ReplyDelete
  4. 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.

    ReplyDelete
  5. 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.

    ReplyDelete
  6. 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.

    ReplyDelete
  7. 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.

    ReplyDelete
  8. 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.

    ReplyDelete
  9. 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.

    ReplyDelete
  10. 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."

    ReplyDelete
  11. 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.

    ReplyDelete
  12. 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.

    ReplyDelete