Proper Hashing

2009-05-03 00:05:54

Wed, 18 Feb 09 13:38:51 -0700

Every good web developer hashes his passwords before storing them.

Popular hashes are md5, sha1, whirlpool, sha512, md160, etc.

For those of you that don't know, a hash is a one-way encryption that is used to protect password data. When a user puts in a password, the system hashes the provided password and checks it against the stored one. If there is a match, the script logs the user in.

This provides a huge security boost over plaintext password storage. For one, if your database is hacked, it is much more difficult for the attacker to steal log in data, also hashing is an effective defence against SQL injection on the password field (if done properly).

Hashes are also often used to validate forms to protect from CSRF, a randomized hash is placed in a hidden input, and is used as a requirement for form submission.

In any case. your hash being cracked is a very, very bad thing.

To combat this, good security experts use a salt. A salt is an extra string added to the hashed value to make it harder to break. A normal hash is usually psuedo-random, like "*ll28@*s 27wd" but this still has a critical flaw: all the characters are on the keyboard.
Meaning, that no matter how long or complex it is, if someone has the will, they will crack it. There are already rainbow tables out there with every US keyboard character on it to 27 characters in length, probably some out there with much more. Not to mention simple brute-forcing.

A distributed cracking attempt via botnet could crack even the longest passwords in a matter of hours.

That is how real hackers do it.

The current solution is to use stronger and stronger hashes. 10 years ago, md4 was state of the art, then md5, followed by sha1, now we have things like whirlpool, md160, and sha512. All 512bit hashes, far from the 32bit md5.

There is still one problem: no matter how many bits you have in your hash, no matter how long your salt, it can all still be brute-forced.

As always, I have a solution for you.

All brute-forces out there assume one thing: that all the characters used in your hash are printable. In other words, they assume that all the characters can be found on a keyboard.

As things stand now, they do.

I propose an alternate solution. A solution that can make any hash many times stronger than before.

Salt the hash with non-standard characters.

This is simple to do:
(php)



$salt = "\0\x06\x08\0f";
$hash = hash('whirlpool', $password . $salt);




aaand you're done.

You can even improve the method, simply open a random image, copy maybe 10 of those random symbols, save them to some random (read-protected) file, use file_get_contents() to get the string and salt it with that.

Also, you could base64_encode() the same data and base64_decode() before adding them to the hash to reduce server usage.

Any way you look at it, the difficulty to brute-force the hash just went up several billion times.

Even if an attacker knew the exact salt, the whirlpool hash still gives a large degree of protection as the collisions on whirlpool are extremely scarce, making it that much more secure.

Cheers

 
Post A Comment!