SHA-512 w/ per User Salts is Not Enough

Posted: May 10, 2011 in Mozilla
Tags: , , ,

Back in January, I was having a causal conversation about passwords at a local gathering about security and was asked what we use for storing the passwords. I stated that we are using sha-512 w/ per user salts but we are looking at moving away from this standard to something much stronger. The response that I received from this person was pretty much in line with other comments I have received and seen on some of our forums. The two most common responses are: “Oh good, you are using per user salts” and “yeah, using sha-512 is much better than md5.” Granted, these comments are true, using sha-512 is better than using md5 and better than not using per user salts but there is still a weakness that I feel is overlooked.

Per user salts do provide value, but the problem is that they are typically stored with the hash. So the entry in the database looks something like this:

sha512${salt}${hash}

Or perhaps the hash is stored in a separate column or table and is grabbed as needed during password verification. Either way, both the hash and salt are stored in the same database.

In the event the hash was disclosed or the database was compromised, the attacker will already have one of the two values (i.e. the salt), used to construct the hash. All the attacker needs to do now is figure out the password entered into the hash formula and the order in which it was used. Order being:

hash = hash_operation({password} + {salt}) or;
hash = hash_operation({salt} + {password})

The two issues with this are: 1) since our source code is public, the order in which we salt is also public and; 2) due to our scale and usability, we store the hash and salt in the same place.

What am I getting at? The real problem is that we shouldn’t be solely replying on hashing algorithms to secure this data. Once the salt is known, it would be pretty trivial to dictionary a bunch of hashes in little or no time and get a pretty significant hit rate. (More to follow on this subject to follow in another post)

What is the solution? Right now the solution is moving away from sha-512 w/ per user salts to something like bcrypt but with a twist. The twist is adding in a layer of defense plus adding some controls over who can unlock the password equation. In pseudo code, this is what I mean:

{hmac_result} = hmac_create_operation( user_password + system_shared_password )
{bcrypt_result} = bcrypt_create_operation(( hmac_result + salt ) bcrypt iterations)

The bcrypt result would be stored in the database like this:

bcrypt$bcrypt_result$shared_key_version

The system_shared_password (aka nonce) is not stored within the database. Instead this data is stored on the operating system within a protected file. Using this configuration a SQL injection vulnerability that provides access to the password hash data would not provide access to the system_shared_password. Only under the scenario of a full system compromise would both secrets (password hashes, system_shared_password) be compromised.

We feel this solution gives us better controls around who can unlock the hashes and provides a layer of defense around the hashes. We also have put some code together thanks to fwenzel:

Why use per user salts at all? Two reasons, first per user salts ensure that two users with the same password will not have the same hash. Second, the use of salts prevents an attacker from using a precomputed rainbow table against the hashes.

More to come on this subject, as our goal is to increase security and the time in which it would take in order to brute or dictionary the hash. Our goal is and always to provide better protection around authentication systems.

Chris Lyon
Director of Infrastructure Security
a.k.a the hash buster

x-posted to: https://blog.mozilla.com/webappsec/2011/05/10/sha-512-w-per-user-salts-is-not-enough/

Comments
  1. Salted hashes are indeed a problem, but not because the algorithm is known or salt is known. They are simply too easy (=fast) to brute force attack if you get the database.

    bcrypt and similar solve this problem by making brute force attacks infeasible because nobody has the computational power to do it. I think you may be overcomplicating this by adding a layer above bcrypt.

    See http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html

    • Chris Lyon says:

      We are not trying to over complicate it, what we are gaining is a separation of who can unlock the hashes. A good example of this is that only the system admins have the keys to unlock the hashes and the dev teams don’t. So if the database wasn’t moved from a prod to a dev environment correctly, it won’t work.

      So we are just forcing the issue.

      and yes, agree, hashes are simply just weak.

  2. “Instead this data is stored on the operating system within a protected file.”

    Will this still be within the profile directory, or will we no longer be able to copy a profile directory from one computer to another and have it just work?

  3. me says:

    You can also use iterations to the process to slow down the attacker.

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