secure hashes in PHP using salt
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.
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 ???
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.
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?
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/
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.
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.
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.
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!
Thanks Kricke, Let me see what happen…….
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?
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.
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?
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.
I found this very interesting , thank you. Would like more information like this.
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
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
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
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.
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!
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.
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.
Justin: Probably because it’s not meant to solve bruteforce attacks.
Ghogilee: Thanks for the FYI.
Good article.
Hey! This post taught me a lot. Thank you very much for it!
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
Very usefull post. I am using it in my site. Thanks for the work
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?
Very nice article! Very helpful!
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.
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
Thx a lot it’s really easy to understand and very effective.