Bcrypt. It’s The Bare Minimum.
The other day I read this Arstechnica article and realized how tragic the situation is. And it is not this bad because of the evil hackers. It’s bad because few people know how to handle one very common thing: authentication (signup and login). But it seems even cool companies like LinkedIn and Yahoo do it wrong (tons of passwords have leaked recently)
Most of the problems described in the article is solved with bcrypt. Other options are also acceptable – PBKDF2, scrypt. And using salt is a must, obviously. Note that bcrypt is not a hash function, it’s an algorithm that is specifically designed for password storage. It has its own salt generation built-in. Here are two stack exchange questions on the topic: this and this. Jeff Atwood has also written on the topic some time ago.
What is salt? It’s a random string (series of bits, to be precise, but for the purpose of password storage, let’s view it as string) that is appended to each password before it is hashed. So “mypassword” may become “543abc7d9fab773fb2a0mypassword”. You then add the salt every time you need to check if the password is correct (i.e. salt+password should generate the same hash that is stored in the database). How does this help? First, rainbow tables (tables of precomputed hashes for character combinations) can’t be used. Rainbow tables are generated for shorter passwords, and a big salt makes the password huge. Bruteforce is still possible, as the attacker knows your salt, so he can just bruteforce salt+(set of attempted passwords). Bcrypt, however, addresses bruteforce, because it is intentionally “slow”.
So, use salt. Prefer bcrypt. And that’s not if you have to be super-secure – that’s the absolute minimum for every website out there that stores passwords. And don’t say “my site is just a forum, what can happen if someone gets the passwords”. Users tend to reuse passwords, so their password for your stupid site may also be their email of facebook password. So take this seriously, whatever your website is, because you are risking the security of your users outside your premises. If you think it’s hard to use bcrypt, then don’t use passwords at all. Use “Login with facebook/twitter”, Mozilla Persona, OpenID (that is actually harder than using bcrypt) or another form of externalized authentication.
Having used the word “minimum” a couple of times, I’ll proceed with a short list of things to consider in terms of web security that should be done in addition to the minimum requirement of using bcrypt-alikes. If you are handling money, or some other very important staff, you can’t afford to stay on the bare minimum:
- use https everywhere. Sending unsecure session cookies can be sniffed and the attacker can “steal” the user’s session.
- one-time tokens – sends short-lived tokens (codes) via SMS, or login links – via email, that are used to authentication. That way you even don’t need passwords (you move the authentication complexity to the mobile network / the email provider)
- encourage use of passphrases, rather than passwords – short passwords are easier to bruteforce, but long passwords are hard to remember. That’s why you could encourage your users to use a passphrase, like “dust blinds horror buildings” or “beautiful dump fire diver”, which are easy to remember, but hard to attack. (My signup page has an example of a subtle encouragement)
- require additional verification for highly-sensitive actions, and don’t allow changing emails if the login was automatic (performed with a long-lived “remember-me” cookie)
- lock accounts after failed consecutive logins – “bruteforce” should only be usable if the attacker gets hold of your database. It should not happen through your interface.
- use certificates for authentication – public-key cryptography can be used to establish mutual trust between the user and the server – the user knows the server is the right one, and the server knows the user is not a random person that somehow obtained the password.
- use hardware tokens – using digital signatures are the same as the above option, but they store the certificates on hardware devices and cannot be extracted from there. So only the owner of the physical device can authenticate
Web security is a complex field. Hello world examples must not be followed for real-world systems. Consider all implications for your users outside your system. Bottom-line: use bcrypt.
The other day I read this Arstechnica article and realized how tragic the situation is. And it is not this bad because of the evil hackers. It’s bad because few people know how to handle one very common thing: authentication (signup and login). But it seems even cool companies like LinkedIn and Yahoo do it wrong (tons of passwords have leaked recently)
Most of the problems described in the article is solved with bcrypt. Other options are also acceptable – PBKDF2, scrypt. And using salt is a must, obviously. Note that bcrypt is not a hash function, it’s an algorithm that is specifically designed for password storage. It has its own salt generation built-in. Here are two stack exchange questions on the topic: this and this. Jeff Atwood has also written on the topic some time ago.
What is salt? It’s a random string (series of bits, to be precise, but for the purpose of password storage, let’s view it as string) that is appended to each password before it is hashed. So “mypassword” may become “543abc7d9fab773fb2a0mypassword”. You then add the salt every time you need to check if the password is correct (i.e. salt+password should generate the same hash that is stored in the database). How does this help? First, rainbow tables (tables of precomputed hashes for character combinations) can’t be used. Rainbow tables are generated for shorter passwords, and a big salt makes the password huge. Bruteforce is still possible, as the attacker knows your salt, so he can just bruteforce salt+(set of attempted passwords). Bcrypt, however, addresses bruteforce, because it is intentionally “slow”.
So, use salt. Prefer bcrypt. And that’s not if you have to be super-secure – that’s the absolute minimum for every website out there that stores passwords. And don’t say “my site is just a forum, what can happen if someone gets the passwords”. Users tend to reuse passwords, so their password for your stupid site may also be their email of facebook password. So take this seriously, whatever your website is, because you are risking the security of your users outside your premises. If you think it’s hard to use bcrypt, then don’t use passwords at all. Use “Login with facebook/twitter”, Mozilla Persona, OpenID (that is actually harder than using bcrypt) or another form of externalized authentication.
Having used the word “minimum” a couple of times, I’ll proceed with a short list of things to consider in terms of web security that should be done in addition to the minimum requirement of using bcrypt-alikes. If you are handling money, or some other very important staff, you can’t afford to stay on the bare minimum:
- use https everywhere. Sending unsecure session cookies can be sniffed and the attacker can “steal” the user’s session.
- one-time tokens – sends short-lived tokens (codes) via SMS, or login links – via email, that are used to authentication. That way you even don’t need passwords (you move the authentication complexity to the mobile network / the email provider)
- encourage use of passphrases, rather than passwords – short passwords are easier to bruteforce, but long passwords are hard to remember. That’s why you could encourage your users to use a passphrase, like “dust blinds horror buildings” or “beautiful dump fire diver”, which are easy to remember, but hard to attack. (My signup page has an example of a subtle encouragement)
- require additional verification for highly-sensitive actions, and don’t allow changing emails if the login was automatic (performed with a long-lived “remember-me” cookie)
- lock accounts after failed consecutive logins – “bruteforce” should only be usable if the attacker gets hold of your database. It should not happen through your interface.
- use certificates for authentication – public-key cryptography can be used to establish mutual trust between the user and the server – the user knows the server is the right one, and the server knows the user is not a random person that somehow obtained the password.
- use hardware tokens – using digital signatures are the same as the above option, but they store the certificates on hardware devices and cannot be extracted from there. So only the owner of the physical device can authenticate
Web security is a complex field. Hello world examples must not be followed for real-world systems. Consider all implications for your users outside your system. Bottom-line: use bcrypt.
Nice overview. I’ve specially enjoyed the «encourage use of passphrases» part. I’m so tired of finding well-known sites that tell you “your password can have up to 8 characters” or “your password cannot contain spaces”.
I cannot take this “article” seriously when I read about the usage of salt. Everyone knows that using salt it’s irrelevant.
@F really? I consider making an attacker’s job as hard as possible to be relevant. Did you not read the point on rainbow table attacks?
I think your math is off on that passphrase stuff. Normal English text like “dust in the wind” or what-have-you clocks in at around 1 bit of information per character, making phrases like that extremely insecure (~16 bits). On the other hand, grabbing four or five random words from a dictionary is relatively secure (e.g. “correct horse battery staple” has ~44 bits according to XKCD). The point here is that you didn’t pick these words and they don’t usually show up in that order in normal English, but it is easier to remember than ~7 random characters that would give you the 44 bits otherwise.