Better Hashing Password in PHP

Every developer should know that storing any type of password in plain text is the worst possible decision anyone can make in a secure environment. Between security and confidentiality which one will you choose? Nowadays hacking are perform through social engineering or an inside job, by an employee or trusted person. How exactly confident are you towards securing your stuff and confidentiality of your user? Most of us will know that the Reddit suffer from such problem when all their username and password were compromised as their password wasn't hashed and stored as plain text. And twitter was attacked through social engineering recently. We won't want this to happen to us right? Therefore, in this article you will get to know some ways to better hash your password in PHP and some ways to improve your security.

What is Hashing?

Hashing is a term used in encryption to perform a deterministic procedure that takes an arbitrary block of data and returns a fixed-size bit string. Any accidental or intentional attempt to change the data will change the hash value. Moreover, different message will have different hash value. There should not be an exact hash value with different message. And it is infeasible to find a message that has a given hash. Hence, many information security application uses hashing to protect or authenticate the confidentiality of the content of the application such as digital signatures, message authentication codes (MACs), and other forms of authentication.

Authenticate User

We use cryptographic hash function to hash our password. And all of us should not be aware of what is being placed as password in the table. So how do we authenticate these users password since hash value is a one way encryption? This can easily be achieve through comparing the hash value against the one user has keyed in and the one stored in our database!

Rainbow table Attack

A rainbow table attack is a form of lookup table that aim to decode the hash value in order to make hashing feasible to find a message that has a given hash. Rainbow table attack is usually used against cryptographic hash function after they have retrieved a hash value. However, we can better protect ourselves by adding SALT onto our plain text to make it more infeasible for rainbow table to retrieve pain text with a given hash value.

SHA-1 and MD5

We all know that hashing is necessary in term of any password. But i would still like to stress such importance. We are very dependency on encryption algorithm such as MD5 or SHA-1. However, these two algorithm is no longer that secure as compared to the older days. On Wednesday, February 16, 2005 SHA-1 has been broken by three china research. Although its more towards collision attack rather than pre-image one we can assure one thing is that SHA-1 can be broken and its weaker than we thought. You can read more about it on Bruce Schneier article. On the other hand, you can find MANY MD5 cracker online nowadays through Google. eg. md5crack.com. But similarly they are all collision attacks or rainbow table. Wiki explains MD5 vulnerability in a way you will discourage using it. Its time to encrypt your users password using SHA-2 such as sha256, sha384, sha512 or better.

Hashing your password

If you are using PHP 5.12 or above, there is a new function, hash that supports SHA-2.

$phrase = 'This is my password';
$sha1a =  base64_encode(sha1($phrase));
$sha1b =  hash(’sha1′,$phrase);
$sha256= hash(’sha256′,$phrase);
$sha384= hash(’sha384′,$phrase);
$sha512= hash(’sha512′,$phrase);

For people who are using PHP 5.12 and below, you can try to use mhash which is an open source class for PHP.

$phrase = 'This is my password';
$sha1a =  base64_encode(sha1($phrase));
$sha1b =  base64_encode(bin2hex(mhash(MHASH_SHA1,$phrase)));
$sha256= base64_encode(bin2hex(mhash(MHASH_SHA256,$phrase)));
$sha384= base64_encode(bin2hex(mhash(MHASH_SHA384,$phrase)));
$sha512= base64_encode(bin2hex(mhash(MHASH_SHA512,$phrase)));

SHA-2 should be used to secure your future application. However MD5 and SHA-1 can still be use for authentication purpose with a very secure password combination. eg. (eQ@xC#Eif2dsa!e2cX2?"}23{D@.

NOTE**: NEVER DOUBLE HASH!

Double hashing is *worse* security than a regular hash. What you’re actually doing is taking some input $passwd, converting it to a string of exactly 32 characters containing only the characters [0-9][A-F], and then hashing *that*. You have just *greatly* increased the odds of a hash collision (ie. the odds that I can guess a phrase that will hash to the same value as your password).

sha1(md5($pass)) makes even less sense, since you’re feeding in 128-bits of information to generate a 256-bit hash, so 50% of the resulting data is redundant. You have not increased security at all.

Credit goes to Ghogilee

****updated on 8 Oct 09

On the note of Ghogilee, i found a few errors which i would like to point out. Double hashing here is referring to two different hash function.  It does reduce the search space but doesn't *greatly* increased the odds of a hash collision.  On the other hand, SHA-1 should be a 160-bit hash not 256-bit and not only does this doesn't increased the security but also weaken the hash function as the hacker will only required to crack the weaker hash function in this case md5.

If you wish to understand the risk and stuff you can do with hash function, please visit Enhance Security Hash Function For Web Development. Here i document the most detail hash function i could for your information.

Enhance Hashing With Salt

Once you have decide your secure password encryption algorithm, the last thing you might want is to have different user having the same cryptographic hash code in order to defend against rainbow attack. This can bring another problem of more than one account being compromised at the same time when there are multiple same hash and short password can easily be cracked with ease when your database and tables have been known. We can generate a salt in order to overcome this problem so that the string is longer and more random (providing that the salt + password are random enough).

define('SALT_LENGTH', 15);
function HashMe($phrase, &$salt = null)
{
$key = '!@#$%^&*()_+=-{}][;";/?<>.,';
    if ($salt == '')
    {
        $salt = substr(hash('sha512',uniqid(rand(), true).$key.microtime()), 0, SALT_LENGTH);
    }
    else
    {
        $salt = substr($salt, 0, SALT_LENGTH);
    }

    return hash('sha512',$salt . $key .  $phrase);
}

The above function contains two parameter. The first will take in a phrase and generate a SHA-2 salt only if the second parameter is placed with an empty variable. However, if both parameter contains values, it will be used when you wish to compare between two hashes. We can use the above method this way,

$username = cleanMe($_POST('username'));
$password = cleanMe($_POST('password'));
$salt = '';
$hashed_password = HashMe($password, $salt);
$sqlquery = 'INSERT INTO  `usertable` ("username", "password", "salt") VALUES  ("'.$username.'", "'.$hashed_password .'", "'.$salt.'") WHERE 1';
..

The above will insert the information into the table when user is being created. We will check the user with the following salt.

$username = cleanMe($_POST('username'));
$password = cleanMe($_POST('password'));
$salt = '';
$sqlquery = 'SELECT `salt`, `password` FROM  `usertable` WHERE `username` = "'.$username.'" limit 1';
..
#we get the data here and placed into variable $row
$salt = $row['salt'];
$hashed_password = HashMe($password, $salt);
if($hashed_password  == $row['password']){
#verified
}
else{
#ACCESS DENIAL
}
..

The objective of salt is to lengthen the password in the table and also creates totally random hash code for each password. Furthermore, a key is being placed in as hash value to protect the password as our SALT is placed in the table and if our table is compromised, the SALT will also be take into consideration in a rainbow table. Therefore, an additional key is required that is not placed within the table. This way, even if your table is being compromised, it will really takes a lot of time for them to crack those hashed password. As i mention earlier, database can be easily compromised due to employee or social engineering.

Summary

Many of us should start moving forward to new hash function rather than sticking on to MD5 and SHA-1. Although it is still secure for these two algorithm to be used given a strong password. Nonetheless, in the near future these two might not be that secure anymore. Furthermore, both algorithm had already been dropped by US and focus on SHA-2 instead. On the other hand, SALT can really help in many ways against social engineering and inside job attack. Its not all about Session attack, SQL Injection, XSS or XRSF nowadays.

11 thoughts on “Better Hashing Password in PHP

  1. Hi Clay,

    i once wrote a password hashing class that can be found here:
    juliusbeckmann.de/blog/easy-to-use-and-secure-php-hashing-class.html
    Maybe it makes the hashing process easier.

    And i found a few points in your article that i disagree with. I wrote a Blog entry about them:
    juliusbeckmann.de/blog/easy-to-use-and-secure-php-hashing-class.html

    Regards, Julius.

  2. I believe your comment wrote for this article is located at

    http://juliusbeckmann.de/blog/correct-hashing-passwords-in-php.html

    instead? Apologize for my comment as i read the wrong article given by your comment which doesn't really look like an article reply. Firstly, rehashing is good but DOUBLE hashing is bad. May be there is a misunderstanding in this article. Double hashing refer to different hash algorithm used. Using two hashes weakens the password as they only need to break the weaker hash. On the other hand, rehashing (uses only 1 hash algorithm) will help strength dictionary and brute force attack.

    Let's look at brute force attack. Assuming our database has been compromised. What do you do if such situation happen? If a system that doesn't employ SALT technique to strengthen their password, they will basically send an email to all their user (REDDIT did that) and inform them to change their password. On the other hand, if SALT technique was employed. You can immediately change the SALT algorithm on your system without any necessary action required from your users. So once your SALT algorithm has changed and we assume the hacker know the length of your SALT but you did not change the length (assume the length is 1000 character). The hacker began to hack your system using the passwords they receive. Let's assume there are around 92 character you can fill for your SALT or password (Its more than 92 characters, please refer to ASCII values). Hence, 1 single character will make a brute force run 92 times to get a shot of a single character password (means no salt). Now, we have 1000 character for our SALT. This means that our hacker will have to try 92^1000 to get a shot to decrypt one password on the list of hacked passwords. This means they will have to try 10^1500 which is many many combination for just one password! I don't think one year is enough for them to crack one password using a single computer. But correct me if i'm wrong.

    Next, let's look at rainbow table attack attempt to crack such password. Now, we understand that rainbow table precompute hash chain. The goal is to precompute a data structure that, given any output h of the hash function, can either locate the p in P such that H(p) = h, or determine that there is no such p in P. Since all our password are salted uniquely, the attacker will have to generate a rainbow table for each salt for each possible password - exponentially increasing the effort an attacker must make. Furthermore, looking at the size of the SALT, it is infeasible for such attack to occur because of the sizable investment in computing processing, rainbow tables beyond fourteen places in length are not yet common. So, choosing a password that is longer than fourteen characters or that contains non-alphanumeric symbols may force an attacker to resort to brute-force methods.

    The last problem with all the above is that OUR TABLE HAS BEEN COMPROMISED. This means that our salt was also compromised. However, this doesn't mean that your security is also compromised! It really depend on how you implement your SALT to secure yourself! Let me give you a LIVE example! Assuming we have a table that contains all the information about username, password, salt, email, telephone, gender, address, etc. Now, with all these data we can create a much secure SALT than the one mention in this article. Since our SALT is 1000 character with any combination of ASCII values. The next thing is to combine the SALT with the LIVE data on the table to popular the correct password. Assuming we take your secret code answer and your username plus your salt and password to generate validation on your user access. This means

    hash(username + database password + salt + secret code) == hash(username + user key in password + salt + secret code)

    The sequence of data and the algorithm use to generate your password is totally unknown to the hacker! Unless, you whole system + database stolen.

    Lastly, the reason why we need to move to a new hash function such as SHA-2. SHA-1 and MD5 has collision problem which every hash function will face eventually due to Pigeonhole principle but how resistance the hash function is makes a differences. In term of collision problem, we are talking about two different password having the same hash value. And this is bad. This means that different password can access a single account. However, this kind of collision is quite rare but not impossible. Having an algorithm that doesn't face collision problem means that is cryptographically safe to assume one password to one hash value.

    I think i will just write an article on this. This seems really interesting! Anyway, your class look secret now that i write this but as usual the salt length and algorithm might be something you need to improve on.

  3. Thanks for this - anything is better than the plaintext authentication I've been using & this article has easy to understand code with great examples :o)

  4. Hey!
    Thank you for this great article.
    But there is one thing I simply don't get.
    "return hash('sha512',$salt . $key . $phrase).$salt;"
    Why do you just attach the salt at the end of the hash? Potential attackers would be able to find out the salt.

  5. Sore, i'm confuse myself! LOL, i guess i confusingly added that part. You are right, there is no point writing a salt at the end of the hashed password. You only do that when you are performing a iterative hashing to enhance each hashing complexity. On the other hand, you might want to visit Enhance Security Hash Function For Web Development where you learn a much detail about salting etc.

Comments are closed.