Plain text is NEVER an option
In last Christmas (2011), there was a breaking news (reported: 1, 2, 3) that over 6 million online user credentials were leaked out from CSDN, a popular China online community for programmers that stores user credentials in plant text, resulting in 50 million user accounts (users use the same credential for multiple websites, including social networks and personal emails) put under security risk.
As we never know when and how hackers steal the user records in the database, storing user credential information in plain text format in the database is never an option for any reasons.
Encryption of password
As a good practice, the user credentials should be encrypted to write to the database so that even the database records are exposed by hackers, the user credential is still less risky. There is many ways to encrypt password, namely using a hash function, adding static salt, adding dynamic information.
Hashing a password is the way to convert the password from a human-recognizable strings (e.g. “QuoKa88$%”) into a set of non-recognizable strings (e.g. “398db0fdd8a26857080a77fd4996377d”) so that hackers who steals the user credential cannot recognize the actual password string.
<?php $password_hashed = md5($password); ?>
However, it’s clearly stated in the PHP documentation that solely using these functions to secure password is not recommended as they can be easily hacked by modem computer’s computation abilities.
One of the attack that breaks the hashed password is called “Dictionary attacks“. Generally users tend to adopt meaningful words as the password to that they can easily remember it. Hackers collect million pairs of meaningful words and their hashed string to build a “hash dictionary”. So when they obtain a hashed password, they can look up the “hash dictionary” and find out the original password.
Adding salt to the hashed password will make the password more secure against the dictionary attack. Salt is additional strings, generated randomly, added to the password so that the password will no likely exists in the “hash dictionary”.
There are two ways to add salt to a password. The first is to add the salt to the original password so as to make the original password longer in length (increase the password complexity) and less likely to be found in an ordinary dictionary. The second is to add the salt to the hashed password so as to make the “hash dictionary” malfunction.
<?php $salt_before_hash = "eGj1&E2%k@"; $salt_after_hash = "12fd53a3b"; $password_hashed = md5($salt_before_hash.$password) . $salt_after_hash; ?>
Adding dynamic information
Adding salt to password, either before or after the hashing, has one potential vulnerability : the salt is a static string (no matter how complicated it is) that the hacker can easily identify the salt by comparing the multiple hashed passwords. Once the table of user credentials is being stolen, hackers only need a few days (if not a few hours) to break the salts.
To fix this vulnerability, we could use dynamic information (such as date of account created, record row ID, user ID, check sum of the password itself etc.) which is static to one user but dynamic to other users.
<?php $salt_before_hash =$userID . $date_user_account_created; $salt_after_hash = dechex(crc32($password)); $password_hashed =md5($salt_before_hash.$password) . $salt_after_hash); ?>
Finally we can add interference in the whole process to make further secure the password encryption. Commonly used interference include re-odering the sequence of the strings and cut the hashed password to a long-enough length.
<?php $salt_before_hash = substr($userID . $date_user_account_created, 5,10); $salt_after_hash = dechex(crc32($password)); $password_hashed =strrev(substr(md5($salt_before_hash.$password)) . $salt_after_hash, -25)); ?>