I have implemented the login/verification aspect of a two factor auth system as per RFC 6238.

It works fine with Google Authenticator, which is great.

Now I am turning my attention to the backup codes, that are provided by services implementing 2FA such as Google and GitHub.

I notice they are of a different length and/or format to the usual 6 digit direct authentication code.

So, do I:

  • Generate an arbitrary number of codes when a user sets up 2FA
  • Store them in the DB alongside the user
  • Make use of the fact they are a different length or format in order to decide how to check them?

Are they supposed to be random, or generated based on some hash of the user?

  • Because Google can regenerate new codes for you on command, one would think they're randomly generated. – Eric Lagergren Jul 7 '14 at 19:16
  • What are you trying to do? Why do YOU want to generate backup codes? Store them in the DB? Are you writing your own backend? – cornelinux Jul 20 '16 at 12:00

Usually the backup codes are opaque random credentials, not mathematically based on the 2FA seed or anything else known about the user, and generated with sufficient length and entropy as to avoid dictionary attacks.

Treat them like single use passwords- hash them before storage so you don't have the originals; discard after one use in authentication; limit the number of and rate of authentication attempts; and allow authenticated users to generate a new set, which invalidates the previous set.

  • 5
    “hash them before storage” make sense to me. But I was confused why some services' implementation of backup code (e.g. Dropbox) displaying them whenever you try to access. Which seems at least they are not using in-reversible hashing. – GaGa_Ek Jun 26 '17 at 18:11
  • 1
    Does hashing them really make sense? The seed for something like TOTP is probably stored in the same place, and that can't be hashed. Additionally, cracking a short number, no matter the hash algorithm, is going to be trivial. The only way around this for short numeric backup codes would be to use reversible encryption. – Zenexer Jul 16 '18 at 0:44
  • Work-factor hashes are not trivial to crack. And "cracking a short number"- the answer recommends "sufficient length...to avoid dictionary attacks." That said, the larger point is that if a system owner stores sensitive keys without best-practice protection, the system owner is committing the equivalent of malpractice. Nearly all security is economic- make this system more expensive than others to the extract value from. One has to actively resist the "it's easy to do it this way" because that also makes it easy for one's adversaries. – Jonah Benton Jul 16 '18 at 3:21
  • JonahBenton What about @Zenexer's first point about the seed for TOTP being stored in the same place? It seems like that would be the common case, and attackers could just generate normal 2FA codes rather than using the backup codes. You could encrypt the seed before storing it in the database, as a limited measure of protection, though. – MaxGabriel Aug 1 '18 at 22:04
  • Yeah- the thing you're solving for isn't someone living in your systems with full visibility to everything. It's more limited than that. A database and its backups are artifacts- files- that as artifacts are frequently the thing-that-is-compromised. What you want to make sure is that someone with a backup of your database can't just pipe import it into mysql and "select password, totp_seed, backup_2fa_code from user". Making it hard for someone with your database to attack you or your users is a good thing. So- yes- encrypt the TOTP seed. – Jonah Benton Aug 1 '18 at 22:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.