Strong Password Hashing with Apache Shiro

A few days ago on the Apache Shiro mailing list, one of our users expressed concern about the points surfaced in this blog article. They wanted to know if Shiro could address these concerns (answer: it can, and has always been able to do so - keep reading for how).

If you'd rather not read the article, the basic idea is that a strong hash algorithm (e.g. SHA-256, SHA-512) and salting is not enough for the most secure password hashing. You basically need to ensure a time component exists as well - i.e. it should take a relatively long period of time to create the hash, since this is the only thing that can slow an attacker that has access to very fast modern hardware.

The author advocates using the BCrypt hashing algorithm to address this issue. It is not that BCrypt is some special hashing algorithm, but that it is slow by nature. The fact that it takes a long time is what is important: when attackers use brute force to crack passwords, the longer it takes them (especially when they use fast modern commodity hardware), the longer you have to react and hopefully address the issue before (m)any of your passwords are cracked.

Despite the perhaps slightly FUD-based tone of the article - the author is correct assuming the attacker has direct access to your password store. This is a big assumption - most organizations go through great lengths to ensure access to say, databases, is levels of security 'deep' beyond just a web login form. Anyway, assuming that this might ever happen to you, how can you address the issue using Apache Shiro?

Apache Shiro Hashing

Apache Shiro has supported a solution for this issue from the very beginning of its hash support. In addition to supporting salts, Shiro's Hash implementations also support an iterations component. This means in addition to a strong hash algorithm and a salt, you can specify the number of iterations a hash should occur. This basically means "how many times do you want the data hashed before being considered as 'done'".

Here is an example of how a hash looks using Apache Shiro:

new Sha512Hash(source, salt, iterations);

Very easy!

The more iterations, the longer it takes to compute the hash, and the longer it would take an attacker to brute-force your passwords (a good thing). So if you want to ensure a strong password hashing strategy, use a lot of iterations. The trick is finding a balance - too many iterations, and the login process feels slow to your end-users. Too few, and you could be weakening your password security.

How many iterations is enough?

That depends. Of course no one likes that answer, but it is entirely dependent upon your application environment, primarily:

  1. How long your login process takes today without multiple hash iterations, and
  2. The CPU speed of the hardware is that hosts your production application.

Your end goal is to slow down the login process enough such that the delay doesn't bother or frustrate end-users. Only you will know your app well enough to know what that threshold is. For public consumer websites, maybe this is half of a second (0.5 seconds). Unfortunately it is very subjective, and you'll need to find out that threshold based on your app.

So what should we start with?

200,000 iterations?

While you could specify 1024, 2048, or even 32,536 iterations on your personal development box (which might sound like an insane amount to you), you'll find that these numbers are probably way too slow for production hardware.

I ran a little test over the weekend. On my dual-core Macbook Pro (2.8 GHz Intel Core i7) laptop, I had to specify 200,000 iterations before the average hash time was 0.28 seconds. And that was just 0.28 seconds! Imagine how fast it would have been on production-grade hardware.

The basic idea now is that you should play with your own hardware environments and see how long it takes in those different environments and tweak according to your requirements.  Starting at 200,000 or 300,000 is probably a good idea.

Part 2

There are options to make passwords even more secure than this (albeit at a complexity cost).  Feel free to read Strong Password Hashing: Part 2 for other techniques.

Leave a comment