cult3

Why do you need to Salt and Hash passwords?

Jan 21, 2013

Table of contents:

  1. What is the problem?
  2. Hashing passwords
  3. Salting
  4. Types of hashing algorithm
  5. Example code
  6. Conclusion

Storing user passwords is a critical component for any web application. When you store a user’s password, you must ensure that you have it secured in such a way that if your data is compromised, you don’t expose your user’s password.

There have been many high profile cases of websites and web applications that have had their user details compromised. This is made even worse when the developers of the website have not stored the user’s password in a secure way.

If you are developing a website or web application that needs to store user data, it is incredibly important that you take the correct precautions should your data become exposed.

This is a guide to storing passwords securely and an example using PHP.

What is the problem?

When developing websites or web applications it is important to always have the outlook that everyone is out to get you. Generally you should assume that every point of your code is vulnerable to attack. You might be thinking, “there’s no way that anyone could get access to my database!”, but this is not the right attitude to have.

When you store a password in a database, you never want to store it in plain text. Storing a password in plain text would mean that anyone who looked through the database would be able to just read the user’s passwords.

Similarly, there are many ways to secure a password from prying eyes, but not all of them should be used.

If you do not take the right precautions when storing passwords, you could expose your user passwords to an attacker. Many people use the same email and password combination all over the Internet. If you expose their password, they could be left vulnerable on other websites or web applications as well.

It is your responsibility to take the right precautions!

Hashing passwords

“Hashing” passwords is the common approach to storing passwords securely. A “Hash” is a one-way function that generates a representation of the password. So when a user signs up for an account and they choose a password, the password is stored as the generated hash, rather than the actual characters that the user typed in. When you run a password through a hashing function, it will always produce the same output. When the user tries to log in with their email and password, the entered password is hashed again and then compared to what is stored in the database. If the two hashes are the same, the user has entered the correct password.

Hashes are impossible to convert back into plain text, but you don’t need to convert them back in order to break them. Once you know that a certain string converts to a certain hash, you know that any instance of that hash represents that string.

Hashing a password is good because it is quick and it is easy to store. Instead of storing the user’s password as plain text, which is open for anyone to read, it is stored as a hash which is impossible for a human to read.

Unfortunately, hashing a password is not nearly enough. It does not take very much computational power to generate a table of hashes of combinations of letters, numbers and symbols. Once you have this store of hashes, you can then compare the hash you want to crack and see if it matches. Once you find a match, you know the password.

Salting

In order to make it more difficult to expose a hash, you also need to salt it. Salting is where you add an extra bit of data to the password before you hash it. So for example, you would append every password with a string before hashing it. This would mean the string prior to hashing would be longer and therefore harder to find a match.

When the user comes to log back into your system, you simply take their entered password, append the salt and then hash it to see if it matches the hash you have stored.

Why is Salting important?

Salting is important because it adds a whole new level of required computational power in order to expose the hash. By adding a salt, you effectively render any lookup table useless. Hashing a password is not 100% secure as hashing alone is not that difficult to break. When you add a salt to the hash, you make it much more difficult to crack.

What should I use as a Salt?

Choosing the right strategy for salting is very important. Salting works best when the salt is completely unique for that user and for that instance of setting the password.

Many insecure systems do not use completely random salts. For example, I’ve seen systems that either use just the email address as a salt, or ever worse, they use the exact same string as a salt for every user. This is effectively pointless because once the salt is known for every user, it does not take much to generate a hash look up table. You also want the salt to be completely unique too. People use the same emails or usernames across many different websites. By using the email or username as the salt, you are opening the opportunity for a pre-made lookup table to be used.

Instead you should generate a unique salt for each user, and a unique salt whenever that user requires one, for instance when they change their password. There are many ways to do this which I will cover in the sample code at the end of this post.

How should I store a Salt?

You might be thinking, “If someone gets a hold of my hashed passwords, how can I also stop them from getting my salts? Where do I store them?”. The simple answer is, you can store your salt in the same User record as the User’s password. The added complexity of storing the salt in a different database is not worth the hassle.

If your user table is exposed by an attacker, having the salt and the hash still means they need an incredible amount of computational power in order to find the password. It is common practice to just store the two fields in the same table.

Types of hashing algorithm

There are a couple of different types of hashing algorithm that you should be aware of. Whilst hashing a password with any of these algorithms will render the password impossible to read for a human, you should still be careful about which one you choose because they are not all secure.

For a long time, MD5 was commonly used throughout the internet. However, MD5 is now accepted as being broken and too vulnerable to attack.

Another set of hashing algorithms is the SHA family.

Whilst it’s important to understand which hashing algorithms to avoid, I don’t think it is necessary to know the ins and outs of every single one. Generally you shouldn’t be making your own password encryption code because without expert knowledge of how the whole thing works you could be leaving yourself exposed. It’s much easier to just use a prewritten safe solution that I will show you below.

Example code

A nice prewritten solution for hashing passwords and creating salts is PBKDF2 (Password-Based Key Derivation Function 2). PBKDF2 is a key derivation function that was written by RSA Security.

As I mentioned above, there’s really no point in trying to write your own secure method when experts have already created a nice and easy to use solution for you.

So first thing we need to do is to create a new class to hold our methods and properties.

class Security
{
}

The first method we need to create is the PBKDF2 method for creating secure hashed values. This method takes a password, a salt, an iteration count and a derived key length. Also, as you can see I’m setting the default hash algorithm to sha256, but this can be overridden.

/** PBKDF2 Implementation (described in RFC 2898)
 *
 * @param string p password
 * @param string s salt
 * @param int c iteration count (use 1000 or higher)
 * @param int kl derived key length
 * @param string a hash algorithm
 *
 * @return string derived key
 */
public function pbkdf2($p, $s, $c, $kl, $a = 'sha256') {
    $hl = strlen(hash($a, null, true)); // Hash length
    $kb = ceil($kl / $hl); // Key blocks to compute
    $dk = ""; // Derived key
    // Create key
    for ($block = 1; $block <= $kb; $block++) {
        // Initial hash for this block
        $ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);
        // Perform block iterations
        for($i = 1; $i < $c; $i ++)
        // XOR each iterate
        $ib ^= ($b = hash_hmac($a, $b, $p, true));
        $dk .= $ib; // Append iterated block
    }

    // Return derived key of correct length
    return base64_encode(substr($dk, 0, $kl));
}

Next we need a method for creating salts. Our salt just needs to be a unique string.

public function salt() {
    return uniqid(mt_rand(), true);
}

Now to use our Security class, we could do something like this.

// The password the user entered
$user_password = "fsdfdsjs";

// Instantiate a new Security object
$s = new Security();

// Generate a Salt
$salt = $s->salt();

// Generate a secure password
$secure_password = $s->pbkdf2($user_password, $salt, 1000, 32);

// Store secure password and Salt in database

Now the next time the user attempts to login in we can just grab a copy of the stored password and salt based upon the email address or username the user entered from the database.

Next we can simply run the password the user entered through our hashing method and compare the entered password with the stored password.

if ($s->pbkdf2($user_password, $salt, 1000, 32) == $secure_password) {
    // Correct password
}

Conclusion

And there you have it, a simple and secure way to store your user’s passwords. Storing passwords shouldn’t be difficult and should be a problem you can solve once. However, if you don’t do it properly, you could face a serious backlash should your database ever be compromised.

In this tutorial we used the PBDKF2 method for hashing passwords, but there are other ways too. One such method is using Bcrypt which I will cover in a future post.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.