I've found (and disclosed) what I think is an interesting little security flaw in Facebook's Two-Factor Authentication usage.
First thing's first, this isn't a show-stopping bug. It's more of a curiosity which shows how different providers treat the verification of Two-Factor Authentication.
If you are a security conscious user, you should have set up Two-Factor Authentication (2FA). Every time you try to log in to Facebook, after providing the correct password, you are send a security code via SMS. If you enter the code correctly, you're let in. It looks a bit like this.
If an attacker has hold of your password, she still won't be able to access your account because she doesn't have access to your phone.
However! There is more that Facebook could do to ensure that these codes are secure. The vulnerability I discovered was that Facebook doesn't verify that the IP or User-Agent which enters the code is the same as the one which requested it.
Alice has a mobile phone on IP address 198.51.100.1 - she access Facebook through her web-browser or app. She enters the correct password and is sent a one-time code via SMS.
Bob has a laptop on IP address 203.0.113.5 - and is looking over Alice's shoulder. He accesses Facebook in his browser and copies Alice's password. When he sees the SMS come through, he quickly types it in and now has access to her account.
What Facebook should be doing is checking that the user who submits the token is the same user who requested the token.
An easy way to do this is to check that both request and response came from the same IP address.
To ensure that this cannot happen when two users have the same external IP (for example they are both on the same WiFi connection) Facebook should also check that the User-Agent is identical - that way a laptop cannot easily use a code intended for a specific model of phone.
Finally, to defend against an attacker having the same IP and the same device, the screen which asks for the code could have a hidden field which provides yet another proof that the submitter is the same as the requester.
Does It Work Elsewhere?
It is possible that other sites which use 2FA are also deficient in the same way.
I tried on Twitter and found that the 2FA code was tied to the browser which requested it - but not to the IP address.
For example, requesting a 2FA code from Firefox will generate a code which didn't work in a Chrome session. However, a code requested from Firefox still worked in the same browser even if I manually roamed onto a different WiFi network and subsequently got a new external IP address.
A couple of weeks after disclosing this to Facebook, I received the following reply:
This is not an exploit an we will not be rewarding this.
There are tradeoffs between security and usability and we've made a decision here; we are confident that two factors is sufficient to secure the accounts, and recommend that users keep their two-factor secrets, their password and their phone, secure.
Inhibiting account authentication on the basis of IP address would have undesirable consequences for the victims, and even for non-victim users.
While I would have loved to been included on Facebook's Hall of Fame, it's not hard to see that this is, at best, a relatively minor security flaw. It relies on an attacker being able to discover or intercept two separate pieces of information.
But there's no reason to make it easy for an attacker who has got that far.
As Twitter has demonstrated, tying the response to the requesting browser is a cheap and easy way to defeat an attacker. Personally, I would also ensure that the request and response came from the same IP address - although I can see certain situations (like mobile users) where that would be inconvenient.
I hope I have demonstrated why it's important to thoroughly verify credentials.