8

For a long time hash functions have required a work-factor in order to keep the operation "slow" enough to protect individual passwords in the case of a database leak. Bcrypt and PBKDF2 being notable examples.

I'm also aware of the "Don't Roll Your Own" when it comes to security, but it's easy to imagine a situation that over time the work factor of your password hashing scheme becomes too quick because of hardware increases. One could also imagine a situation where the owners of the database upgrade their own hardware and thus a higher work-factor is suitable compared to what was being used before the hardware upgrade to ensure better safety per-password.

The problem comes with having to "re-hash" a password, because you don't want to store a plaintext or even an encrypted password in a database so the system has no way to access the password again for rehashing to change the work factor. To fix this, simply do this re-hashing when a user logs in. Whenever the user logs in their plaintext password is already available to the system, on a successful hash verification of the password the system can check the previous work-factor associated with the hash of the password (easy to do in bcrypt) and if it is less than the standard work-factor selected by the system operators then the plaintext password is rehashed and stored with the new work-factor and new salt. Sessions don't need to be reset as the same password is being used as before, just a different work-factor and salt.

Apart from the plaintext password being in memory for slightly longer during the verification of the password and an increased time in verifying the password whenever a work-factor increase is issued, I can't find any faults of this model. Are there any security flaws that I have missed?

sethmlarson
  • 1,479
  • 10
  • 17

2 Answers2

4

You seem to have summed it up pretty well.

The only drawback I can think of is inactive users in your system - they will continue to have a previous work factor because they may never log in again, or may not have chance to log in before your next breach, meaning their stored password is more vulnerable to attack. As work factor is visible within the stored data, the attacker would know which ones are using the old setting (although they will not know the relative entropy within each password).

To prevent this, you could regularly disable accounts that have not been logged into for say 6 months, blanking their password at the same time. If they need to login at a future time, they can simply go through your forgotten password functionality to enable a new password to be set and stored with the new work factor.

SilverlightFox
  • 33,408
  • 6
  • 67
  • 178
  • In addition to this, I'd note that it's worth re-evaluating *which* password storage function you're using periodically too, to keep in line with modern practices. Additionally, once you've verified that no users in your database have old hashes any more (this helps if you implement the lockout and blanking method), you should remove the code from your system which handles the older hash verification. – Polynomial Apr 07 '16 at 14:43
  • This is exactly what I was thinking of. Pairing this scheme with a lockout that perhaps requires an email verification if it's been too long since the last login. Definitely a little leaving in usability, now suited for a more secure environment. – sethmlarson Apr 07 '16 at 15:00
2

A key point is that you have the password hashes in your database so you do not have to re-hash the password. Lets say you have hashed them (correctly, with salt ect.) N times. To double your work factor you can rehash the hashes N more times in the database. And then apply this same rehash to logins in the future. See https://crypto.stackexchange.com/questions/3003/do-i-have-to-recompute-all-hashes-if-i-change-the-work-factor-in-bcrypt and Is it possible to increase the cost of BCrypt or PBKDF2 when its already calculated and without the original password? for more details.

AstroDan
  • 2,226
  • 13
  • 24
  • Initial thoughts are that bcrypt (N+1, password) isn't the same as bcrypt (N, bcrypt (N, password)). Haven't looked into if there's an easy way to extend a hash in that way without knowing the password. – sethmlarson Apr 07 '16 at 15:03