Nathan Wong is the co-founder and head of the tech side of BSA. He wrote an informative piece about some changes with password security at BuySellAds. You can see the original post, and Nathan’s other writings, over at Nathan.ca
Image courtesy of WickedVT
As of this morning we have officially migrated everyone’s password at BuySellAds over to bcrypt. I’m almost ashamed it took us so long – especially since it turned out to be so straight-forward to switch. If you still believe MD5 or SHA-1 is sufficient for passwords, read this post and get to work.
The final push that motivated us to switch to bcrypt was Kickstarter’s security breach. I was watching our always-endearing tech community lambast them for storing nearly-plaintext passwords when it hit me: we’re storing nearly-plaintext passwords. Damn!
The next day I put in an open-ended ticket to figure out a migration plan for switching to bcrypt. One of our developers, Jon Hehir, handled most of it from there.
The premise is simple: in order to avoid having any MD5-hashed passwords in the database at all, simply bcrypt the old hashes, and continue to double-hash passwords when new ones come in. This is in contrast to the common advice to “version” passwords and only update them when people login (i.e. when you have a plaintext version of the password on hand). It’s highly likely that you have older users who will never login again, though, and they deserve their password to be stored properly too.
In PHP, handling bcrypted passwords is easy:
password_hash($input, PASSWORD_BCRYPT, array('cost' => 13));to encode the given password that you want to store in the database.
password_verify($input, $storedhash);to compare whether the given password matches the hash you stored in the database.
- If you aren’t on PHP 5.5 yet, include the compatibility library too.
Coupled with the migration strategy above, that’s all you need to know. The above functions handle hashing, salting, storing the salt, versioning, and everything else you need. It really is that easy – arguably simpler than what we had before – so there are no excuses.
In our case, we did run into one additional snag where we were storing cookies that contained a hash of a login salt and the user’s hashed password. We’ve since switched to storing a unique random hash in the cookie instead. This did, however, delay our ability to remove the old passwords from the database for users who we knew had logged in recently. This meant we had to wait until we knew their cookies had all expired to avoid logging them out prematurely.
Nonetheless, I’m extremely relieved to know that we no longer have any nearly-plaintext passwords in our database or in our cookies. I expect to sleep a little better tonight. If you’re still using MD5 or SHA-1, what are you waiting for? Go switch to bcrypt now!