What's the optimal length for a 2FA code?
The other day, a company sent me a 2FA code which was only four digits long.
I'll admit, this weirded me out. Surely 4 is just far too short. Right? I think almost every 2FA code I've seen has been 6 digits long. Even back in the days of carrying one of those physical RSA fobs, 6 has been the magic number.
But why?
A 2FA code is meant to prevent a specific class of problem. If an attacker has got hold of something you are (your username1) and something you know (your password), you are still protected by something you have (your phone). Whether your second-factor is an app generating unique codes, a SIM card receiving SMS2, or a cryptographic enclave producing signed transactions - it doesn't matter. The attacker can use your password but won't get the unique second code.
Suppose you received a 2FA code that was a single digit. Is that secure enough?
I think most reasonable people would say that wasn't secure. An attacker has a 10% chance of guessing the 2FA. If the system allows for a couple of retries before locking them out, they've got a 30% chance of getting in.
Similarly a 2 or 3 digit code probably doesn't provide sufficient protection.
A typical bank card PIN is 4 digits. So an attacker has a 1 in 10,000 chance of guessing. That might be slightly better as bank PINs usually don't allow repeated digits, palindromes, and a few other combinations.
I suppose that if an attacker had compromised tens of thousands of credentials, and the service allowed for a few incorrect entries, it is statistically likely that they might be able to compromise a few accounts if they were only protected by 4 digits.
As 2FA codes get longer, they begin to reach the limits of what humans can remember. Yes, I know you have an excellent memory - but not everyone does. And I know your fancy 2FA app automatically copies and pastes the codes - but not everyone does. We have to work to what the average user is capable of at a minimum.
I think most people would find it annoying - if not impossible - to remember a 10 digit one-time password.
If you're copying a code from your phone to type into your laptop, there's probably an upper limit on what people will be prepared to do. No one is going to manually transcribe 128 digits. And, if they did, they'd likely introduce several errors.
So the industry has seemingly settled on 6 digits. I've ranted before about the lack of standardisation in the OTP specification. But all of them seem to allow 6 - 8 digits.
I suspect 6 is the standard because that's what the original RSA SecurID tokens used by default.
An attacker would have to be incredibly lucky to randomly guess a 6 digit code - literally a one-in-a-million chance3. Even if they had multiple retries, it's still statistically unlikely.
Once I logged in using my 4 digit code, I had full access to my account. But if I wanted to make any changes, I had to wait for another 2FA code to be sent. So I guess the effective length of code was actually 8 digits. Which seems excessive 🤣
Thoughts from the community
I asked my Twitter buddies for their wisdom:
What do you think?
- Traditionally, the something you are is a biometric. However biometrics are static - they never alter. So they're poor for some choices of authentication. A username represents something you are. Everyone can see your username - just like everyone can see the fingerprints you leave on every touchscreen and the DNA you shed all over the place. ↩
- Let's gloss over SMS being a bit vulnerable for now. ↩
- Although, as per Terry Pratchett: "Million-to-one chances crop up nine times out of ten.". ↩
Harley Watson 🏴🇪🇺 said on twitter.com:
docs.microsoft.com/en-us/azure/ac… is maybe interesting for only using two digits, albeit the interaction model is the inverse of typical SMS 2FA
R says:
GitHub (Microsoft owned) also uses 2 digits: https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication#verifying-with-github-mobile
Mike Nolan says:
CAF Bank send a 6 digit code on login plus a 7 digit code for each transaction you approve. By SMS. From a sender which Android's messages app doesn't auto copy to clipboard. With a non-responsive website that requires pinch-zoom into every input field.
Alison W (♿️⚾☕♀️🏳️🌈🇪🇺🇵🇸💙💛🌻) said on twitter.com:
Although UK bank cards have 4-digit PINs my Swiss account card had six digits, which felt safer. My problem is the five minutes thing if I have to search for the phone or, for emailed ones, if it doesn't arrive quickly.
Jack said on twitter.com:
GitHub's 2FA code is only 2 digits when you use their app as the MFA provider for your account docs.github.com/en/authenticat…
Christopher M0YNG said on mastodon.radio:
@Edent clearly 6 is optimal because you didn't write a blog post about it. 4 clearly FELT less secure, enough to trigger a blog post.Don't discount the theatre aspect of making people FEEL more secure.Although personally I have to do 6 digit ones in two chunks so 4 would be preferred.
Steve Scott said on twitter.com:
Yes and no. They use the app as the 2fa, and store a secret there. The code is to stop someone just idley clicking accept when someone else tries to 2fa. Believe it or not, pressing accept rather than 'I didn't request 2fa, ohshit' seems to be a thing people do.
Fazal Majid says:
A better question is, why would you use a code-generating 2FA, as they don’t authenticate the server and you may be looking at a phishing site proxying the real site in real-time? Only U2F/Webauthn keys guard against this and hardly anyone uses them, which shows 2FA is all too often performative security theater.
Radu says:
Why do they have to be digits? If using let’s say 4 alphanumeric characters instead of digits would’t it be easier to remember/copy and more secure cause there’s ~1.6m combinations?
@edent says:
Thqt can work. But there are two major issues.
Homographic confusion. Is it 0 or O? 1 or I or l? Z or 2?
Not everyone using your service will have a Latin keyboard - but nearly everyone will have Arabic numerals.
More comments on Mastodon.