Implement two-factor authentication now!01 Jun 2015
2FA, two-factor authentication (or two-step verification as it’s also called) has been in the news regularly lately, as more and more sites implements it - unfortunately usually after being hacked.
(Google explains quite well what it’s all about.)
So why should one want to implement 2FA? Well…
Slack recently enabled 2FA after a serious security breach in February. Last October JPMorgan disclosed the biggest U.S. banking breach of all time, and the hackers were able to gain access after finding a server unprotected by 2FA. In January 2014 the @N twitter account was famously stolen, with the rightful owner concluding that this would not have been possible, had he enabled 2FA on all accounts. Twitter implemented 2FA in 2013 following a number of high-profile hacks, as did Dropbox (weeks after being hacked), LinkedIn (about a year after being hacked) and Evernote (three months after being hacked).
The list goes on, and continues to grow - and what they all have in common is that the hacks could have been prevented if 2FA had been implemented and enabled before the hacks. Please make sure your application does not make the list!
Technically 2FA is very easy to implement using existing libraries, and there is really no reason not to. And you can easily verify that your implementation is generating the one-time passwords correctly by using e.g Google Authenticator on your phone - if they generate the same numbers, it’s working…
There are some additional things you should consider, though.
Generating the shared key.
The key used to generate the one-time passwords needs to be correctly generated in order to generate secure passwords. If it’s not, it might be generating passwords easy to guess (silly example: if you accidentally use the same key for all users, they will all get the same passwords). Unless you really know what you are doing, you should not try to roll your own key-generator.
Luckily, you do not have to do this yourself - there is a good spec, reference implementation, and a number of open-source libraries available. Wikipedia is a good starting point, and you can have a look at the Porotype TOTP example.
Sharing the key or delivering the password
There are basically two ways to get the one-time passwords to the user:
- By sharing a secret key, so the user can use an app (e.g Google Authenticator) to generate the passwords.
- By sending each generated password via SMS when the user needs it.
Option 1 is easy to implement - you only need to get the key to the user securely once. Usually by showing a URL and/or QR-code when 2FA is enabled by the user. It can also be sent via another channel (like snail-mail) or fetched in-person for ultimate security.
Option 2 might be a bit harder to implement (at least you need reliable SMS sending capabilities), but for many users this is much easier. Setting up an app and understanding how it works might prove overwhelming.
One important step, where things can go seriously wrong, is the point when 2FA is enabled for an account. At this point you need to make sure the user has understood and has everything set up in working order. Usually you require the user to input a one-time password (“logging in” once), before actually enabling 2FA for the account.
Phone numbers change, and phones break, go missing and get stolen - sooner or later you will need to recover an account for a user. If you make it too easy you might as well not have passwords at all. Make it too hard, and a lot of users will end up locked-out.
Google, for instance, allows users to print a list of back-up codes.
Finding the right requirements and procedures for account recovery is ultimately up to you, and should be done up-front and with thought. You can always change your policy later.
Asking for a one-time password at login along with username and (regular) password is not the only way to do it. And chances are it’s not the best way to do it either.
When and how often to ask for a second authentication really depends on your application. What follows is food for thought - consider how secure your application should be, and apply as appropriate in your case.
Starting up the 2FA application, or waiting for an SMS, can be annoying, and asking at each login might not be needed. Some applications has a “Remember this device [for some amount of time]” option - you will be asked again when logging in from another device (or browser), or when the application deems it necessary. Some applications get suspicious when a user logs in from a different location (e.g country, based on ip address), for instance.
Another thing to consider is that login might not be the only critical operation. You might want to protect some other opration(s) by asking for authentication at that stage. The obvious example being changing password, and disabling 2FA - you should definitely ask for authentication at that point. Some other examples: making a payment, publishing an article, deleting an item, and so on.
In fact, depending on what your application does, you might not want to use 2FA at login at all, instead asking for it when really needed, for maximum protection with minimum annoyance.
For instance, the Nordea Mobile Bank app allows the user to log in and view account balance and transactions using just a pin code - but to make a payment, you need to be fully authenticated, and the app will ask for passwords when needed. It’s a smart way of minimizing the friction, while protecting the important stuff.
As mentioned earlier, 2FA might be a difficult concept to grasp for some users - especially if it involves installing apps on your phone. Printed password lists might be an option, and there are also dedicated hardware devices available. Please consider both your security needs and your target audience when sorting out the details for your implementation.
Please implement two-factor authentication as soon as possible in your applications. Technically it’s really simple to do - the main challenge, really, is to achieve suitable usability. As any security measure, 2FA is only effective if it’s being used.