12

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?

2
  • Because Google can regenerate new codes for you on command, one would think they're randomly generated. Jul 7, 2014 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, 2016 at 12:00

1 Answer 1

14

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.

7
  • 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, 2017 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, 2018 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. Jul 16, 2018 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, 2018 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. Aug 1, 2018 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.