Password Security Part 3: The Anatomy of a Hash
In part one of our series on password security we looked at why we should be using bcrypt. In part two, we looked at how to implement it in PHP, Ruby, and Ruby on Rails. In this third part, we will take a look at the result of applying the bcrypt algorithm: the hash itself.
The Hash
The hash is made up of multiple parts. These parts allow you to determine the settings used to create the hash, thereby allowing you to validate against it without needing any additional information.
The prefix, $2a$
, identifies that bcrypt is used, and which version. This is followed by the cost, the salt (21.25 characters), and finally the hashed text.
In June of 2011 version 1.1 of crypt_blowfish was released that fixed a bug in the handling of non-ASCII characters causing insecure passwords. To be able to identify potentially buggy, known buggy, and correct hashes, two other prefixes were introduced.
- $2a$ — Potentially buggy
- $2x$ — Known buggy hash
- $2y$ — Using the corrected version
Because the ruby gem did not suffer from the bug, it only supports the $2a$
prefix and also supports validation of the $2x$
prefix for compatibility.
PHP supports all three prefixes. While password_hash()
outputs correct hashes using the $2y$
prefix, it will validate $2a$
and $2x$
hashes for backwards compatibility but password_needs_rehash()
function will return true
—indicating that you should rehash and convert to the correct version.
Two-Factor Authentication
While you should definitely be using bcrypt for the storage of your passwords, you should also be using two-factor authentication (2FA) in tandem for increased security..
2FA relies on a secondary authentication mechanism in addition to the password. A password is something the user knows. The secondary authentication mechanism could be something the user has (such a device that issues time-based tokens) or something the user is (such as the types of things biometrics can measure). Biometrics are not commonly used with web applications, so we’ll focus on time-based tokens.
Traditionally, this would have been something like an RSA SecureID device. This is a keyring sized gadget that generates and displays a new token every 30 or 60 seconds for the user to enter upon login. This token is derived from a shared secret that only the server and the device knows. And by knowing the current time, the server can figure out which token should currently be displayed.
More recently, we’ve seen the addition of numerous other options, including soft tokens (such as Google Authenticator), mobile phone app push notifications (such as the Twitter app for iOS) and SMS based verification, whereby a code is sent to a users known cell phone number via SMS and then input. All of these, in one way or another, attempt to verify that the user is in posession of something, be that a mobile phone or a token generator.
Conclusion
To be responsible application developers, we owe it to our users to keep their information safe. Using SSL to avoid sending data (e.g. passwords) as plain text and mitigate against man-in-the-middle (MitM) attacks is not enough. We should be hashing their passwords using bcrypt, and preferably adding two-factor authentication to our apps.
As we have seen, using bcrypt is trivial in a number of languages, and by using bcrypt we are ensuring password security against the two main attack vectors: dictionary attacks and brute force attacks.
Our users trust us with their most personal information, and we must show them that their trust is well-founded.
P.S. Are you still using MD5 or SHA-1? Has this series of posts convinced you to change that? What about implementing 2FA? Do you use any other mechanisms for keeping your users safe? We’d love to hear!
Share your thoughts with @engineyard on Twitter
OR
Talk about it on reddit