Concerns with two factor authentication in ASP.NET Identity v2
I’ve been doing a bit of research into how ASP.NET Identity v2 is implementing its new features, specifically two factor authentication. I was curious, of course, because I’ve had the opportunity to implement the same feature in MembershipReboot. It’s interesting to see the differences, and as you might have realized (due to this blog post) I have some concerns with the approach Microsoft has taken (which I list below).
Note that ASP.NET Identity v2 is not yet released and this post is based upon the publicly available nightly builds.
Brute force attacks on two factor authentication confirmations
I’ve already commented on this issue here, but I list it here for completeness.
Email used as a second factor for authentication
In the new sample template application for ASP.NET Identity, there are two different delivery mechanisms configured for two factor authentication — one via SMS to the user’s mobile phone (which is a very common and expected approach) and another via email to the user’s registered email account. Using email as an option for two factor authentication surprised me, since I always understood two factor authentication to mean that a user must present two factors from something you have (e.g. key), know (e.g. password), or are (e.g. biometrics). Using the user’s email as a second factor does not achieve two factor authentication (at least according to the strict definition) and if you think I’m splitting hairs, then let me instead illustrate an attack against the email as the second factor.
Imagine an attacker compromises the user’s email (perhaps difficult, but it still happens frequently). Once the attacker has done this, then of course they are in a position to intercept the email based two factor authentication token. But in addition, the user’s password is also essentially compromised because the attacker can issue a password reset which is confirmed via the user’s email (this also illustrates why an identity management system should support password reset secret questions and answers). So controlling the user’s email thwarts both password and two factor authentication code.
If the user’s mobile phone is used instead as the second factor, then even if the user’s email is compromised the attacker would also need to compromise the user’s mobile phone to gain access to the application. This is the point of two factor authentication — it requires more effort of the attacker. Using the email just doesn’t seem very strong to me. I’d suggest disabling the email based two factor authentication and just utilize the mobile phone delivery mechanism.
Time-based two factor authentication codes
For the two factor authentication codes, ASP.NET Identity uses RFC6238 to generate these values (it’s ok, I had to look it up as well). Basically the way this works is that a code can be determined based upon the clock time (given various inputs to seed the algorithm). A code will remain the same for some configurable duration (say for a 5 minute window of time). This window of time is based upon the server clock time and not the time the code was requested. So this means (for a 5 minute window) from 2pm to 2:05pm the code will be a consistent value, but as soon as the clock hits 2:05pm the code will be different but won’t change again until 2:10pm. It’s a clever idea and is similar to how those RSA key chain code generators work.
Update: Scott left a comment below with details about TOTP I wasn’t aware of. It seems that the algorithm allows for old codes up to a certain threshold and it looks like ASP.NET Identity allows for 90 seconds. This means that the usability window for code is much more user friendly than I realized. This allays my concern with this aspect of the two factor auth codes and ASP.NET Identity, but I still feel the next issue is a problem (see below). My apologies to ASP.NET Identity for my misunderstanding and mischaracterization of the TOTP implementation.
My complaint about this approach for two factor authentication codes is that the user doesn’t have any insight into when the window of time expires (whereas they do for the RSA key chain code generators). For example, a user logs into the application at 2:04pm and the code for that window of time is sent via SMS to their mobile device. This means that the user only has 1 minute from the time the server sends the SMS, to receive the SMS, unlock their phone, open their text messages and then enter the code into the web application to prove control of their phone. There will be a certain percentage of users (those those login closer to the end of the window of time) that will not be able to enter their code in time before it changes. And there’s no way for the user to understand that the code they’ve just entered is stale. Oh and the other issue is that the window of time that ASP.NET Identity uses isn’t as gracious as 5 minutes — rather it’s 30 seconds. That’s a very narrow window of time before the code expires. Even if this window is expanded to 5 minutes (which is the expiration of the short-lived cookie as described here), that still means that on average 10% of users will be issued codes with less than 30 seconds to enter them. I can only imagine the questions on the ASP.NET forums asking why sometimes two factor codes work and why sometimes they don’t. Also, I could see how this might become an application support headache. I can only surmise why this was done, but my guess is that ASP.NET Identity took this approach so they would not have to store anything in the database for the two factor authentication code. It’s a tradeoff, but unfortunately I think this is the wrong tradeoff since it makes the developer’s job easier at the expense of user friendliness.
Two factor authentication code generation and all your database are belong to us
So recall how we should be storing passwords — the premise is that an attacker has pwnd your database. This means anything in your database the attacker has. Well, it turns out that the “various inputs to seed the algorithm” that I mention above for the time-based two factor authentication code generation are all either well known constant values or plaintext values from the user’s record in the database. This means if the attacker has access to the user’s record in the database they can calculate the exact same two factor authentication code that ASP.NET Identity generates. This also doesn’t seem very strong to me.
I know there are better approaches (since I built at least one in MembershipReboot), but the tradeoff was that some storage was required in the server. I think that’s an acceptable tradeoff for better security.