Patrick’s development blog

secure hashes in PHP using salt

Posted in Articles, Security by Patrick on February 12, 2008

This tutorial shows the principle of using a salt in order to secure your password hashes. It’s written with my scripting-language of choice which is PHP, but the principle is the same with whatever server-language you might be using. Before going on, i’ll explain some facts that might be good to know before reading the article.

Brute force
Brute force is a comparison technique which goes trough all possible characters and in this case runs trough an algorithm to compare with the hashed password. To put it simply, it compares all different characters until it finds the right password.

One way encryption
The process of encrypting a string so it cannot be decrypted. These are also called hashing algorithms. The most used ones are md5 and sha1. The general difference between these two is that sha1 is generally stronger since it returns a 160-bit fingerprint while md5 is 128-bit. You might ask how we can make use of something that cannot be decrypted. It’s quite easy, we compare different hashes and do not decrypt them.

Whenever you store information about a user in your database. You most likely store the passwords using a one way encryption like md5 or sha1. If not, you really have to think over your security, big time. Still, even if you encrypt the passwords, they can still be cracked using brute force, rainbow tables or dictionary attacks. If we assume the passwords are very sloppy and insecure while the hashes have leaked to the cracker. Unfortunately it’s very uncommon that the users use a smart password, so it’s no use relying on the users.

This is where salt comes in. It simply adds a certain string into the password before hashing it. It’s not any harder to do than regular hashing.

The principle of using salt

// this is what it normally looks like when hashing a string using md5
$password = md5($password);

// using a salt, you instead concentate a string to the password before hashing it
$password = md5($salt.$password);

If we assume $password contains a very weak password, for example “abcdef”. Which would be very easy to brute force. The salt can make this password practically as strong as you want it. There are many methods out there and people constantly invent new ways to generate a salt. In my option, the salt doesn’t need to be that complicated though. The only way someone can brute force the password in this state, is by knowing which salt you use. If they’ve come that far, it wouldn’t matter in any case.

A salt can be as complicated or simple as you want it. Here is an example.

Creating a simple salt

$password = "banana";
$salt = "aB1cD2eF3G";
$password = md5($salt.$password);

This might not be the best and most used salt method out there, but it works. Suppose you use the password “banana” from the example. Then the generated hash would actually become “aB1cD2eF3Gbanana” which is a considerably stronger password than “banana”. This takes care of the user’s bad habit of using easy passwords with only lowercase characters. Just remember that you don’t have to use the salt in the beginning of the string, the principle is the same if you type md5($password.$salt). You can do however you want.

I have seen it’s very common to combine different encryption methods as well. This is in my option very effective. If we create a salt based on the password that uses sha1 and md5 together and then use md5 to concentate these strings like a normal salt. We would get a salt that contains a double encryption of two different encryption methods. The hash we get from this is then added to the password before hashing it once again.

$password = "banana"
$salt = sha1(md5($password));
$password = md5($password.$salt);

This would be equal to a password that is a hash itself + it’s regular password.

md5("f8bbff024e7d04d98a349ccb0984ad85d8ba86fabanana");

Brute forcing the password hash in this case would mean to brute force the sha1 generated string with the password”f8bbff024e7d04d98a349ccb0984ad85d8ba86fabanana”. In other words close to impossible unless you have over million years and a supercomputer at hand. Well, even if you had, you would only get another hash out of the current one, if you want it to be that way.

How to crack salted hashes
The only known way to crack salted hashes is to know the salt algorithm. If the cracker knows this, it’s possible to brute force it by adding the necessary data before starting the brute force process. It’s hard to explain in words so i’ll give another example.

// the regular salt process, this is the “algorithm”
$salt = md5($password);
$password = md5($salt.$password);

// we suppose $test_string is the string it tests
// since this is brute force it’ll be various different strings
// “a”, “b”, “c”, “d” .. “aa”, “ab” … etc

// if md5(md5(“abc”). “abc”) is equal to
// md5(md5($password). $password) then
// “abc” is the password we are searching for

if (md5(md5($test_string). $test_string) == md5($salt.$password))
echo $test_string; // this is the password

To put it simply, if the cracker knows what salt algorithm is used. We will be back to step one and the salted hash is just as vulnerable as the regular md5 hash that isn’t salted. It’s very unlikely that the cracker do know though, i’m just pointing out the flaws.

This is how webmasters can protect their users from evil crackers or annoying skiddies that have come across a cracking program. Not many webmasters secure their website and use salted passwords though, some even leave them in clear text in the database. So i’ll let my next article be about how to create strong passwords so the users themselves can protect their password/account better. Strong passwords should be an obvious thing, but it sadly isn’t.

About these ads

28 Responses

Subscribe to comments with RSS.

  1. Partho said, on February 15, 2008 at 2:50 am

    Really a compact discussion, I learned a lot. Will you write the following-
    how do we compare the encryped password with different hashes by PHP ???

  2. patrickbe said, on February 16, 2008 at 5:01 pm

    I’m glad to hear that you found it useful. When comparing an encrypted password with a hash, you need to encrypt the password before you compare them. If we were to do this in PHP using md5, it could look like this:

    if (md5($salt.$password) == “the hash”)
    echo “The password is correct”;
    else
    echo “Wrong password!”;

    I can make an article about this in more detail if you’re interested.

  3. Partho said, on February 27, 2008 at 5:21 pm

    I enjoy U’r reply. It would be very useful if U make an article on this topic.
    I hv another question – How can I encrypt password before ‘Submitting the Form’, does it need javascript?

  4. patrickbe said, on February 28, 2008 at 7:56 pm

    Yes, Javascript is probably be the best way to encrypt it before submitting. I’m curious why you want to encrypt the password before submitting the form though. Personally I cannot see any use of doing that.

    I’ve never used any cryptographic functions like that in Javascript before, so I cannot really help you with that i’m afraid. It shouldn’t be so hard to pull off though. Find out how to encrypt passwords using Javascript. Then you only have to add an additional field which represents the encrypted password.

    Example:

    Supposing there is a function named MD5 in Javascript :)

    The following site might be of interest if you want to do this.

    http://pajhome.org.uk/crypt/md5/

  5. Partho said, on February 29, 2008 at 2:08 am

    I want to encrypt password before submitting the form, because if I don’t encrypt the password before, the clear text would be submitted; if there is any other alternative, then plzz give me the details.

  6. patrickbe said, on February 29, 2008 at 1:57 pm

    There is no need to encrypt it before submitting, since all login systems submit the password in clear text. The actual login process and encryption this article covers is taken care of by the server code (PHP).

    I’m not sure, but maybe it’s packet sniffing you want to protect against. I don’t know if the following is a reliable solution against that, but it’s certainly what you’re looking for.


    <form action="#" method="POST" onSubmit="this.pass.value = MD5(this.pass.value);">
    <input type="text" name="pass">
    <input type="submit" value="LOGIN">
    </form>

    This code will encrypt the password before submitting it. Use the link I gave you in order to learn about how to use MD5 in Javascript. I cannot help you with that part.

  7. Kricke said, on March 6, 2008 at 2:55 pm

    Reply to Partho.

    You are probably better off using SSL for encryption instead.

    If you can not, it is not sufficient to sha/md5 the password before send, because then an sniffer/man-in-the-middle can use that hash to log on.

    A relatively safe way to do it is that the server sets one random and unique number in a hidden field in the form, and saves this number for say, 1 hour. A javascript on the client (not really good to depend on javascript for accessibility though) then use this random number as a salt and sha1 the password with this and submit the result together with the random number in clear text. The server look up the random number and delete it from the table of issued random numbers (only one time use per random number) and then looks in a database for a password matching sha1(random-number+password). The problem is that a row scan in the database is necessary. To avoid saving clear text passwords in the database, sha1 can be saved and the client then calculates 2 sha1, first only the password, and secondly with the random number as a salt.

    Hope it helps!

  8. Partho said, on March 11, 2008 at 3:30 am

    Thanks Kricke, Let me see what happen…….

  9. Eli said, on April 15, 2008 at 10:21 pm

    Wouldn’t this be just as vulnerable to dictionary attacks as a non-salted password?

    If you use the password as its own salt then a whole hashed string could be figured out pretty quickly and easily for every word in the dictionary. Then all an attacker would have to do is compare that list to the list of passwords.

    If you use a random, unrelated salt, however, then the attacker could only generate a dictionary list that would be relevant to a single salt (or possibly a few) and the process would take much longer. You also wouldn’t need to worry about if they discovered your salt generation process.

    Does that make sense?

  10. patrickbe said, on April 16, 2008 at 11:23 am

    Eli:
    If you’re using a fairly unpredictable salt algorithm, a dictionary attack is quite out of the question unless the attacker knows what salt is used. I assume you mean that the salt algorithm is exposed to the attacker somehow. Well, if that happens it wouldn’t matter what kind of salt you use.

    I agree that a random salt could be good, but a salt related to the password itself shouldn’t be any dangerous IMO, that is if the salt algorithm isn’t easily figured out.

  11. rcg said, on May 26, 2008 at 1:43 am

    I understand the concept of the salt… basically, it makes weak passwords look like strong passwords. A few questions about managing salt:

    1. If it’s derived from the original password, no problem… the salt can be regenerated by the appropriate algorithm. So one could say that the salt is stored in the password.

    2. If you generate a different random salt for each password, you have to store it along with the hash in your password database… does that sound right?

    3. You could use the same salt for all passwords on a specific database, but that sounds risky… is this a practice?

  12. patrickbe said, on May 26, 2008 at 11:13 am

    1. Yes, that’s right.

    If you generate a random salt for each password, you most likely need to store that salt along with the hash, yes. I’m not sure how you do this in practice though because i’ve never found the need to do that actually.

    3. Well, it’s more risky to not use a salt at all. The only way someone can figure out the salt you use though, even if it is the same for all passwords. Is if they access the source of the .php file.

    If you want to be on the safe side, you can always use a unique salt for each password. I think it should be safe enough to use a regular salt however.

  13. ACE-KING said, on July 4, 2008 at 6:57 pm

    I found this very interesting , thank you. Would like more information like this.

  14. Phill Pafford said, on August 13, 2008 at 6:20 pm

    I understand the concept of salt and would like to implement it in my current site. Could you go into more details on how to alter the DB table for the hash and salt. Also if you do a random salt how do I compare this in the DB against the user who is trying to login?

    I see a lot of blogs/tutorials on what salt is but nothing with a end to end overview.

    Thanks in advance
    –Phill

  15. patrickbe said, on August 14, 2008 at 1:18 am

    How to implement this into an actual script is quite easy. If we take PHP for example, you could store the password in the following manner:

    Register a user in the database

    $salt = “Salts are good”;
    $password = sha1($salt.$_POST['password']);
    mysql_query(“INSERT INTO registered_users(password) VALUES(‘$password’)”);
    // … other stuff

    And then when someone logs in, you check if the password is correct by comparing the stored password hash with the hash generated by the typed password from the form.

    The login file

    $salt = “Salts are good”;

    // this is the password the user who tries to log in types.
    // we encrypt this password in the comparison expression later
    // with the same algorithm as the stored password
    $password = $_POST['password'];

    // if this is true, then the password is correct
    // if ‘stored_password’ is the hash stored in the DB already
    if (stored_password == sha1($salt.$password)) {
    print “You are logged in!”;
    }

    I can write a more practical example of using salts someday. Using random salts is something i’ve never tried though. I may write about that as well after some research.

  16. Fred T said, on September 12, 2008 at 3:36 am

    On the topic of random salts. I have used such a system but in my case I am making use of the date and time when the user signed up to have a unique salt for each password. The weak link in this case would be knowing what I am doing to the datetime field to create my salt and finding out the value of signup date to attack the password. To each their own, but one could use the “autonumber” value, or any value from the database row for this user. Dates, IDs, SSN, etc work good for this type of thing and since they are read-only after signup, it works great!

  17. Justin said, on September 14, 2008 at 1:00 am

    I’m not sure I understand the point of all of this. It doesn’t seem to solve any brute force attack at all.

    Ex: Someone has a script that tries tons of passwords on your site. Each time a submission occurs, you salt it and compare to the stored password.

    What good has the salt done? If the TRUE user has password “iamadummy” and the cracker managed to stumble across “iamadummy”, then he’s going to authenticate successfully. Again, how did the salt help?

    The only benefit I see to the salt is if someone actually gets into your database and is trying to crack passwords stored in it. Then, the salt is a little more useful. However, if he’s gotten into your database already, it’s a pretty good chance he can access your PHP as well.

  18. Ghogilee said, on October 1, 2008 at 9:34 am

    The suggestion below to double-hash your password is not a good idea. You are much much better off adding a variable salt to passwords before hashing (such as the username or other field that is dissimilar for every account).

    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.

  19. patrickbe said, on October 2, 2008 at 7:35 pm

    Justin: Probably because it’s not meant to solve bruteforce attacks.

    Ghogilee: Thanks for the FYI.

  20. Heshan Peiris said, on November 29, 2009 at 11:13 am

    Good article. :)

  21. feety said, on December 18, 2009 at 4:38 am

    Hey! This post taught me a lot. Thank you very much for it!

  22. Zach said, on November 23, 2010 at 7:56 am

    Hey, sorry if I’m bringing up something old, but you can use md5 and sha1 together, as long as you are concatenating them and not using one as another’s parameter. (The code is probably a bit more clear)

    I won’t go into the specifics of my hashing algorithm, but what I’d recommend doing for complete security would be the following:

    1. Create a random string to use as your first salt (I call this a “pepper”)
    2. Generate a random string to use as your second salt (this one we will store in our database
    3. Use substr and md5 with your pepper and your salt.
    4. Use sha1 with your salt, password, and pepper.
    5. Append step 3 to step 4.

    Now, the only way for someone to crack your passwords is to either (1) use brute force or (2) gain access to both your code and your database

    In the case of 1, you can easily mitigate this threat with flood control by ip address (for example) on the login and the like. Granted, there are probably ways around this, but brute force is well addressed, so I’m sure you can find other means to protect against it. (Encourage your users to create stronger passwords, for instance)

    In the case of 2, if someone gets your code AND your database… it’s pretty much game over for you, dude. If they just somehow manage to find your pepper, change it and patch up your security so they cant get back in. It’s pretty easy to make up a random string. Just be sure to follow standard “strong password” protocol when making your pepper.

    And now, some quick (pseudo)code in PHP to sum it all up:

    —–
    function generateSalt() {
    return substr(md5(uniqid(rand(), true)), 0, 12);
    }
    $pepper = “y8&K35h@PK1f”;
    $salt = generateSalt();
    $hash = md5($salt . $pepper) . sha1($salt . $password . $pepper);
    —–

    Now, just store your hash and your salt in your database, and you’re good. I’ll leave you guys to authenticating the user. Should be a piece of cake.

    You may even want to mess around with how you store the pepper for a little more security. If you’re on a unix server, you can use chmod to modify permissions of a file containing the pepper, and then just ‘include’ it into your code (similar to how you might store your database credentials).

    No matter what, just keep in mind that even this method will not keep you completely secure. Information is never truly safe on the net, but it doesn’t hurt to deter a few attackers here and there with your security measures.

    Please feel free to post criticisms ;)

  23. jarco said, on December 2, 2010 at 1:40 am

    Very usefull post. I am using it in my site. Thanks for the work

  24. Scottzozer said, on February 28, 2011 at 8:13 pm

    This system seems like it uses the same hard coded salt for all password encryption. Would it be better to get a random salt for each user and just store that in the database so when querying you can check the user name grab the salt from that then check their password and return true or false?

  25. Seanguy said, on March 16, 2011 at 8:51 pm

    Very nice article! Very helpful!

  26. Dom said, on April 21, 2011 at 1:58 pm

    If the “salt” is based on the password itself, then it is not a salt at all, it is a slightly more complicated hashing algorithm.

  27. Aaron said, on May 1, 2011 at 11:36 pm

    Hey, thanks a lot for posting this. I was reading the php.net manuals about sha1 and md5, and there was some discussion of salting, but nobody explained what it was. This is just what I needed.

    Cheers

  28. beast977 said, on May 6, 2011 at 4:21 pm

    Thx a lot it’s really easy to understand and very effective.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: