Monday, August 10, 2009

Ongoing salt discussion

John, one of the guys working on the AllForLocal project, shot me an email recently regarding my decision to drop the salt out of the password hashing process. Here is his email:

Hey,

I'm e-mailing you in response to your blogger post about password salts in the Buy Local project. I tried commenting on the post, but for one reason or another it didn't seem to work (unless it's waiting on you to okay the comment before it shows up). Anyway, since it was something security related I figured it was important enough to contact you about. Here is the post:


Hey there! I just started following this blog (I'm a developer of allforlocal.com and find it interesting to see what you're up to) and I think there might be an oversight here:

It's true that to keep the salt and password hash separate would be more secure, but that isn't the point of the salt (as far as I'm aware). The real value of the salt comes in when you have an attacker who has somehow obtained the password hashes and is trying to work back to the passwords. Once they've gotten to that point they have two choices: Either brute force the hashes (very time- and computation-expensive) or perform a lookup in a hash directory/rainbow table (http://en.wikipedia.org/wiki/Rainbow_table) which can be nearly instant. It's the second attack that salts protect against, even if the attacker has the salt as well.

The reason for this is because hash directories/rainbow tables store passwords and their resulting hashes to do quick lookups, but even a small change to the password (courtesy of salts) totally changes the resulting hash, making these sorts of lookups useless. Plus there's a bit more entropy since the salts are random. The end product is that attackers _must_ use brute force and even that route is made a bit more difficult for them.

So in short: I encourage you to keep the salts! You'll be sweating a lot less if you ever do run into security troubles down the road.


-John


My reply:

John --

I worked with securing web and database applications and servers for the US Department of Labor for three years, and out of that came the following rules I use when evaluating when and how to secure applications:

1) Confidentiality - Upholding privacy of data and preventing unauthorized access;
2) Integrity - Guarding against unauthorized or malformed inserts/updates/deletes;
3) Availability - Preventing crashes and slow performance when accessing data.

The degree to which each of these categories are important depends on the sensitivity level of the application in question. An application that runs the back-end for a credit card company, say, would require higher levels of CIA than a community website such as BuyLocal.

That said, there should be a certain base layer of security in any application. The question is then one of degree, and how much of a benefit is achieved by whatever measure is taken.

When passwords are entered into the authentication system, they are passed directly to the server without being pre-hashed. In order to pre-hash with a salt, the salt value would need to be passed to the authentication system before it could hash the password, and that isn't being done. In most implementations, the login will not be protected with SSL/TLS, which means passwords transmitted in the clear over the Internet, which is a larger threat than obtaining password hashes.

Since hashes are not distributed, and are only used at authentication time, there are very limited paths to the hash data. The hash data could be obtained through a database vulnerability, or a web vulnerability allowing access to database data, such as SQL injection. A backup copy of the database could be intercepted if it were on, say, my laptop, and my laptop were stolen. The problem here is that if the database is vulnerable, the salt column in the users table is just as vulnerable as the hashed password column, and that extra step wouldn't constitute a serious hurdle for any malicious attacker. Same thing with a database backup - the salt values would be right there with the passwords. Security like this is akin to changing the port that your database server runs on or obfuscating the engine for your server-side scripts - a few seconds of scanning with any of many readily available tools gets past these 'protections,' and implementation of the protections proves to be more hassle than it is worth.

Let me give you another 'for instance' - say someone got the password hash and looked it up in a rainbow table. Say the user's password was 'abc123' and the salt is 'f0293fec'. Based on the current implementation of salt ($hashedPass = makeHash($salt . $password)), the rainbow table would return:

f0293fecabc123

If more than one hashed value was obtained, the attacker could quickly figure out that all of the salt values are 8 character hexidecimal predicates to the actual password. A simple perl script that trims off the first 8 characters is enough to turn the rainbow table results into a password list.

I'm a believer in the mantra 'do it right or don't do it at all.' If salts will be re-implemented, they will be implemented after SSL is mandated for the login, and they will be (at a minimum) stored in a separate table, accessible only by using separate credentials (to protect against SQL injection), inserted at a random position, of random length, and preferably, of random quantity - and they will certainly push the password length beyond 64 characters in all circumstances to make rainbow table lookups virtually impossible. However, I don't believe that level of security is required for an application of this type, and I'd rather spend my time working on security measures to protect against more likely vectors of attack - such as SSL/TLS for protecting the login, protecting against SQL injection, protecting against session hijacking, XSS, etc.

No comments:

Post a Comment