Over the past few years, I have given a talk on Cryptography Pitfalls at a variety of conferences. One section of the talk covers the evolution of password storage and the various data breaches the last few years. In addition to covering the ways password storage has been done wrong, I also present the best solutions. Instead of recapping it again, take a look at Coda Hale’s blog post on the topic.

A few brave souls will occasionally come up to me later and admit their company still stores passwords in a less than ideal way. There are many reasons for this, but they generally boil down to the fact that the software is old and developers just didn’t know any better when they wrote that part of the system.

When talking to them about how they plan to solve it, most come up with roughly the same solution: when a user logs in, transparently write an updated bcrypt version of the password to the database. The problem with this solution is that users don’t benefit from the new system if they never log in. When teams upgrade their passwords this way, they will often look back years later and find that some users never logged in again. This is especially true in consumer products.

My advice to them is always the same: don’t wait to fix your password storage. You should instead run the existing password hashes through bcrypt and store that as your password verifier.

For a hypothetical example, let’s say we have an application that was storing passwords as just sha1(password). We could then change the code so that the new format for password storage is bcrypt(sha1(password)). This is perfectly secure and has the benefit that we can derive the value given data we already have. This is a much better solution than silently updating on login. You can do this in three phases:

  1. Deploy the code that can detect which password a user has and verify it correctly. Write new passwords in the updated bcrypt(sha1(password)) format.
  2. Run a background job that visits each record in the users table and updates their password by taking the sha1(password) format and writing back the bcrypt(sha1(password)) format.
  3. Go back and remove the code to detect the two different formats and only ever work with the new format.

Now you have fixed your password storage and every user has the benefit right away.