Salting passwords
The process known as salting provides extra security for protecting your passwords and for that matter any encrypted data. The best way to describe salting is a bit like a key to double lock and unlock data. In fact, if you imagine an average set of house keys – you have a Yale key and an extra key which is often referred to as a deadlock – keys are also unique to their specific locks. Salts will or should be unique to the particular aspects of the application that need them. The salt used in application development is the equivalent of the deadlock.
So how does this work in practice?
In this post we will explore two methods of salting data and examine the pros and cons of each.
Example 1
In the first example we will generate a random string as you might expect to generate a password for a new user. We will take that string and create a substring of eight characters, generate a salt creating a random key. We will then encrypt it using MD5 and then use that salt in combination with our random password – encrypting the whole thing in SHA256.
This is a perfectly acceptable method – to be used in a real application you would need to make sure that every salt generated was stored in the database. For extra security it would be prudent to store the salts in a separate table because if the database was ever compromised it wouldn’t take long for the hacker to work out the salts for each login. The only other slight drawback from this method is there is a greater risk of data collision – in other words the same password or salt key could be generated.
//EXAMPLE 1
//Define length of substring
define("MAX_LENGTH", 8);
//create a random string
//THANK YOU to developphp.com for this function
function generateRandomString($len)
{
$result = "";
//Define string of characters, numbers and symbols
$chars = "abcdefghijklmnopqrstuvwxyz$_?!-0123456789";
//create an indexed array of $chars
$charArray = str_split($chars);
//Using the length argument generate a string using the array_rand to randomly select an element from the $charArray
for($i=0; $i < $len; $i++)
{
$randItem = array_rand($charArray);
$result .= "".$charArray[$randItem];
}
//Return the result
return $result;
}
//usage example
$randomString = generateRandomString(16);
echo "BEFORE SALT: " . $randomString . "<br>";
$encrypted_pass = createHashSalt($randstr);
//Call function generateHashWithSalt
echo "AFTER SALT: " . $encrypted_pass;
function createHashSalt($password) {
$tempSalt = md5(uniqid(rand(), true));
$salt = substr($tempSalt, 0, MAX_LENGTH);
return hash("sha256", $password . $salt);
}
Example 2: BCRYPT
In modern web applications BCRYPT is really the default standard for hashing and salting. What you are getting is two for the price of one. When using PHPs built-in BlowFIsh encryption method it generates its own salt unique to that particular string. Another bonus is that you do not have to store the salts separately which means more optimised code and tighter security.
Let’s take a look:
//Create a sample password
$samplePassword = "SamplePassword267!";
$encrypted_password = generateHash($samplePassword);
echo "AFTER SALT: " . $encrypted_password . "<br>";
function generateHash($password) {
if (defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
$salt = '$2y$11$' . substr(sha1(uniqid(rand(), true)), 0, 22);
return crypt($password, $salt);
}
}
$successFlag = false;
$badPassword = "BadPassword267!";
$successFlag = verify($badPassword, $encrypted_password);
if($successFlag)
{
echo "Login successful";
}
else
{
echo "You're password is not valid!";
}
function verify($password, $hashedPassword) {
return crypt($password, $hashedPassword) == $hashedPassword;
}
Cost Parameter
Another key advantage with using PHP’s crypt is that it uses a technique called costing. What costing does is that it slows down the time taken to encrypt the data. Now, you would be forgiven for thinking that’s daft – why would you want to slow down the encryption?
Well, if you have a bad guy trying to brute force attack your application they will be using an automated script that queries probably as fast as it takes to encrypt a password that is not costed. By slowing down the time it takes to encrypt the data it could have a punitive affect on the attackers script to such an extent that it’s not worth the bother. Though it has to be said with weak passwords the extra benefit of this security is negligible.
In Summary
In summary you should always encrypt passwords. MD5 is not really going to cut it but at the very least SHA256 should be used. Always salt your passwords. You do this by creating your own salts and store them separately but this will be inefficient for large applications. The best method is to use PHP’s Blowfish crypt function which does the hashing and salting for you in one sitting.
In addition to using crypt you also have costing built in (which can be altered up or down). This slows the encryption process down to the extent that it could compromise a brute force attack by slowing the process of the attackers script. Though as identified if the password is weak this will have little effect. To mitigate for this and to get the best out of costing educate your users to create complex passwords. Or create a regular expression that forces them to.