With all the news of hacked databases (mostly at Sony) and the clear-text or poorly hashed passwords in their datasets, I thought I might offer my standard trick for transitioning to a more secure form of hashing. I think some sites don't change passwords security for fear of annoying users or the workload involved in managing a transition. This simple technique is completely invisible to the user and very low maintenance for the developer.
I will be giving examples from the Devise library for Rails apps, since I recently implemented it there.
The technique is very very simple
You configure your authentication to check passwords against both the old and the new form of hashed password. And when you find a match for the old hash you update your database with the version of the password encoded using the new hash. You keep this dual check in place until all (or most likely most) of your users have logged in and had their passwords changed. The unlucky few can use your password recovery feature if you have one.
Metacode of the basic principle:
if new_hash(password) == stored_password // ALLOW LOGIN USING AN UP-TO-DATE PASS else if old_hash(password) == stored_password // UPDATE PASSWORD IN DB // ALLOW LOGIN else // DISALLOW LOGIN end end
How to implement this transition in Devise
I implemented this by overriding the method valid_password? injected into your User model.
class User def valid_password?(incoming_password) result = super incoming_password if !result # try old encryptor during transition digest = Devise::Encryptors::LegacyEncryptor.digest(incoming_password, self.class.stretches, self.password_salt, self.class.pepper) result = Devise.secure_compare(digest, self.encrypted_password) if result # update password to use new encryptor when there is a match self.password = incoming_password self.save end end result end end
Fairly simple. You may need to hard-code some parameters (salt, stretching, pepper) if they cause problems.
If you are changing from, say, sha1 to sha256, you can easily check the character lengths of the passwords in your database to check the "adoption rate" of the new hashes.
Implications on Security
You should realize that you ARE lowering your security level slightly by effectively allowing 2 different password checks. In reality this problem is small and only really matters if you have plain passwords you are transitioning from (and you really shouldn't have). The problem then becomes real since I could login using a stolen new (supposedly) secure hash as the given password. In this case I would definitely disallow any password of the same length as, or simple reg-ex match for, your new hashing system to avoid this hole.
You will also not fully benefit from the new hashing system until you remove the "dual check" after a reasonable period of time.
If you can live with that to gain the benefits of a clean migration for you and your users this is a nice technique. I know from reading and talking to developers that I am far from the only of the first to come up with something like this. Many apps and sites have used and continue to use this kind of technique to beef-up password hash-strength without bothering users.