Wednesday, April 2, 2008

Salt hashed passwords for deep thinkers

| Armando Romeo |
While auditing Joomla source code, I have had the opportunity to make some thinkings on structural security improvements that can be achieved at design-time of a web application, that is when developers usually lay down OOP diagrams. (Is there anyone who still does this in the web app dev field anyway?).

I will start from the concept of salts used in passwords hashes stored into the databases of CMS, forums and every kind of web application that requires some sort of user authentication.


First of all salts are used to give randomness to the password hashes.
The primary reason why they are used is to defeat the larger and larger rainbow tables available on the net.


Some of them seem to arrive up to 14 chars and many of them
are freely available online or even downloadable from torrent.
All the possible combinations of say x alpha-numeric chars are created and hashed. Pairs of plain-hash are inserted into a database (table) that is then indexed through the hash value.
People inserts their stolen hash value and get the plaintext in matter of seconds.
Pretty nice eh?

The x above is the number of characters the rainbow table is able to cover.
As salt, a random value should be used for each user whose password hash has to be computed.

This at least is what common sense tells and what Joomla and other CMS do. Salts in Joomla are same size of hash that is 16bytes, long enough to defeat rainbow tables and any other precomputation/dictionary attack.
So where is the problem?

The way hashes salts are stored into database makes them useful *only* against rainbow tables attacks while a wiser choice at design time could have made password hashes safe against old-fashioned attacks: a hacker manages to get password hash through an sql injection and cracks it locally with some brute forcer. (0phrack can crack the password "Fgpyyih804423" in 160 seconds.)

But here comes the best part. How are salts stored into Joomla database? Answer is: in the same field of the password, divided bye a colon.
To be more clear: salt:pass_hash

At first I thought that placing the salt in the same field of the password introduced some kind of flaw. But in the end I realized that a hacker able to read the password field is probably able to read the whole database. So storing the hash in another field or table

is just useless and doesn't add any real protection. What I can't understand though, is why we have to rely on salts stored into db.
A hacker would just steal the pair salt:pass_hash and then fire up his own favourite md5/sha1 cracker and prepend the salt to the plaintext trials.

Yes salts defeat rainbows. But the way they are implemented doesn't add any further security feature against our old and always handy brute forcers.
If we then consider that passwords chosen by users are usually shorter than 6-7 characters, then you got the picture.

My proposal would be to build the salt so that it is taken *also* (and not only) from a string not readable by hacker. This can be a secret created at the installation of the web application and hardcoded into a configuration file for example. (not world readable of course)

Objection here would be: a hacker finds an sql injection, so he's capable to read database. He registers a new account on site and then reads his own
plaintext(the pass he chose)-hash(salt+pass he chose) pair.

Brute forcing the salt while keeping his password fixed would disclose the salt.
But if this fixed salt is long enough it will be hard to be found through brute force.
With this approach the hacker who has retrieved the password hash, won't be able to use the rainbow table and won't be able to crack it in a reasonable time
using a tool on any available hardware nowadays.
So we achieve both our goals with little change.

If fixed salts for all users may seem too bad for someone, they can be used along with random (per-user) salts stored in db to make up a new salt.
This can be a good tradeoff, a simple way to add more security to passwords that would require few lines of code changes.

However, I hardly believe it will be implemented into already existent web applications since they would break the way how user authentication (login and register) is carried on.
But if you're designing your new web app, why not taking the ideas above into consideration?

Free Security Magazines