2

I'm using bcrypt for some web service requests that hash multiple passwords. The problem is that these web service requests can take minutes to complete due to bcrypt. Not very user friendly.

My question is the following: Can I hash these passwords with SHA and persist them to the database, then have a decoupled queued worker come along and properly hash these passwords with bcrypt?

That way eventually these passwords will be hashed with bcrypt but the user doesn't have a painful experience in the process.

Currently, I'm using the .NET library BCrypt.Net.

enter image description here

  • About how many passwords? Handfuls or hundreds? – Neil Smithline May 05 '15 at 17:29
  • @NeilSmithline These particular requests have at maximum, 10 passwords. – ElectricSignal May 05 '15 at 17:31
  • Now that I think about it, you could also do something similar with a weaker hash algorithm. – ElectricSignal May 05 '15 at 17:36
  • 2
    They shouldn't take that long. Bcrypt is run many times to intentionally slow it down. Perhaps you need to adjust the number of rounds of bcrypt you are running? This [answer](http://security.stackexchange.com/a/17238/10885) has some information on it. – Neil Smithline May 05 '15 at 17:38
  • I'm not certain what a "weaker hash algorithm" means but I don't think there's a need for that and it may cause problems as some hash algos have known exploit strategies (eg: MD5). Just tweak the number of rounds. – Neil Smithline May 05 '15 at 17:39
  • @NeilSmithline sorry what I was getting at was what if during the request I hash with SHA. Then a decoupled process comes along and hashes that SHA hash with bcrypt later. – ElectricSignal May 05 '15 at 17:51
  • You don't want to do that. See this [answer](http://security.stackexchange.com/a/33550/10885) for reasons why combining multiple hash functions produces results with unknown security. – Neil Smithline May 05 '15 at 17:53
  • I think playing with the hash algorithm is the wrong way to go. Even if you manage to do the hash for storage, the operation is too slow for you to do it for login validation. You need to find out why it's so slow. Reducing the number of rounds will likely help. You haven't mentioned the language or bcrypt library your using but you want to use one that is native code, not interpreted. – Neil Smithline May 05 '15 at 17:58
  • Slow-hashes like `bcrypt` are designed to be tuned to meet your specific performance needs. If the default number of rounds is taking too long (*minutes* for 10 passwords is absurdly long), then simply reduce the work factor until you find a better balance. – Stephen Touset May 05 '15 at 20:17
  • Once you've created the password hash, you still need to verify it with the same kind of speed; you should probably just reduce the workload to make it finish in about .01 sec – Jack May 05 '15 at 23:33

3 Answers3

6

Bcrypt is run many times to intentionally slow it down. Perhaps you need to adjust the number of rounds of bcrypt you are running? This answer has some information on it.

While what you propose may work, I can't say that implementing a variant of standard password handling is a good idea. While I have specific concerns, such as the SHA hash staying in the DB too long and the security of the encrypted queue, I generally don't see the need to vary from the standard. If it's taking too long, reduce the number of rounds used for execution. If it's inexplicably slow, figure out why. Don't just decide that you can do better than decades of security best practices. It's not likely to turn out well.

Perhaps you want to post another question (likely on StackOverflow) asking about help with finding the performance problem. That seems a much better idea.

Sorry that I can't agree with your proposal...

Neil Smithline
  • 14,702
  • 4
  • 38
  • 55
  • I should add I don't mind the slowness on verification, only when hashing. I added a diagram to show a possible workflow. – ElectricSignal May 05 '15 at 18:08
  • 2
    I agree with Neil's overall premise of not reinventing the wheel (particularly so in security). In the intermediate step you appear to be countering a reduced work factor (fewer bcrypt rounds) with ephemeral storage (less time for compromise). If for whatever reason you insist on having the very high aggregate bcrypt rounds (i.e. beyond user tolerance) then at least (i) use a truly ephemeral queue storage mechanism (e.g. Memcache with encrypted swap), and (ii) replace SHA with bcrypt at fewer rounds (to be "topped up" later). – Arran Schlosberg May 06 '15 at 01:58
3

The depicted design would entirely undermine the security of bcrypt.

Your design could be simplified by simply eliminating the bcrypt part of the flow and rely only on the SHA hash. That simplification would not change the security of the design significantly, it would still be as insecure as simply applying a SHA hash.

Using a SHA hash with a salt would however be sufficient to protect good passwords. Only weak passwords benefit from using stronger password hashing.

You haven't fully described the problem you are trying to solve, so we cannot provide any solid advice on how to proceed. However two interpretations of your question comes to my mind, and each of them can be answered.

Are you trying to speed up bulk creation of users?

If you are trying to speed up bulk creation of new users and being slowed down by the password hashing algorithm, then I can propose two ways to improve that quite specific use case.

  1. Use strong passwords and a mediocre password hash. If the passwords you generate for the users initially are strong, then you don't need the full security of bcrypt. An initial password with 128 bits of entropy passed through a password hash which does a single salted iteration of SHA-2 is secure enough. Once the user changes the initial password to something else, you can switch to a different password hashing algorithm. This can even be achieved using standard formats for password hashes such as the once used by the crypt function, in which the format starts with a specification of the used hash.
  2. Use a password hash which support fast initial hashing, but is slower at verifying passwords. This can be achieved by applying a SHA-2 hash to concatenation of salt, password, and a short random bitstring. The random bitstring is not stored anyway, so it has to be brute-forced in order to verify a password. This brute-forcing replaces the usual iteration used in password hashes.

Are you trying to reduce CPU load on your server?

There are password hashing algorithms which can securely offload the CPU intensive part of the computation to the client without compromising security. This can even improve security by never allowing the server to see the actual password. The drawback of this approach is, that it requires client side support. A client can no longer just submit user name and password in order to log in.

Which hash to use?

Don't use anything weaker than SHA-2 in any new systems. Any legacy systems using SHA-1 for security related usage should be phased out or upgraded. Any legacy systems using MD5 for security related purposes should have been phased out a decade ago.

The SHA-2 family has six different variants. Don't go with a shorter output because you think it will be faster. In reality there are only two variants of the compression function. One has 256 bit internal state and is optimized for 32 bit CPUs. The other has 512 bit internal state and is optimized for 64 bit CPUs. If your CPU is 64 bits, then SHA-512 is both the fastest and likely to be the most secure.

For password hashing you should never hash without salt. I think that's the only completely objective advice that can be given on how to hash passwords. There is plenty of other advice to be given, but the rest is going to be depending on the threat scenario.

kasperd
  • 5,442
  • 1
  • 19
  • 38
2

The risk here is that if an attacker manages to extract the SHA'd passwords from the database, then they can run a password guessing attack at a relatively fast speed. You should at least salt these password, but then you're increasing complexity which is generally at odds with security. A good secure system should be as simple as possible to make it so.

I don't think that bcrypt(sha-2(password)) reduces security in any meaningful way. Yes you could be reducing the search space from 576 bits to 256 (with SHA-256), however you only need 128 bits of entropy in order to have an "unbreakable" password using today's technology (and that of the foreseeable future). So this is a moot point.

Don't forget that to validate the passwords for log in you're going to have to SHA-2 it (fast) and then bcrypt it (slow) each time for comparison. Therefore your log in system will be slow, although here you are doing bcrypt rather than n * bcrypt, which I think where your problem lies with the batch process.

I think the solution to this is a system architecture issue rather than a security issue. Tune your bcrypt cost so that it takes about 1 second for a valid user to login. Then redesign your batch process so it is asynchronous and it bcrypts the passwords in the background. Have a notification event to return whether this process was successful or not, and if not which user IDs had failures. This will improve your user experience, making your system less secure will not. Memory is much more secure than the DB.

SilverlightFox
  • 33,698
  • 6
  • 69
  • 185