9

I'm working on implementing 2FA with Google Authenticator on our website. If I understand correctly every user will have their own secret code, which I will need on login to verify the 6 digit code they enter.

Storing these secret codes in the same database as the user passwords seems like a bad idea (although, if someone got a hold of the database we have bigger problems), is there anyway around it? Or should they just be treated like a password and encrypted?

blackbird
  • 989
  • 1
  • 14
  • 39

3 Answers3

8

You cannot hash the secret used to generate the TOTP code for Google Authenticator because you need the original secret to actually generate the code.

It pretty much is as you say, if someone has your database then you're in bigger trouble anyway. However this is how 2 Factor Authentication is supposed to work. If the password is indeed hashed securely and the attacker has only the TOTP secret then all they can do is generate 1 out of the 2 factors required to login and they have more work to do to break or steal the password.

If you'd rather not worry about storing these secrets for your users and letting a third party take care of it, can I recommend you take a look at Twilio's Two Factor Authentication API. Full disclosure, I work for Twilio, but if you don't want to worry about looking after secrets that you can't hash, as well as take advantage of other things like the Authy app (including secret transfer without QR codes) and the extra device data that is now available with authentications then it might be of interest.

philnash
  • 53,704
  • 10
  • 46
  • 69
1

You are right.

Is true that the 2FA increase the user security, but is not so strong at server side by definition. If a hacker or malicious employee with database access dump and publish the users secrets, the adtional security is gone.

What can be done ? You can create a external isolated microservice, that receive a user hash and generate a 2FA secret keys, cryptography it and store in a key-value database, like elasticsearch. You can set the cryptographic key dynamically after the server start, to not store it hard-coded. You can store the database at a external server where the employees have no access other than via API.

This way if a malicious actor dump the elasticsearch database, they can not know what is the secret, and even if he gain access to the crypto keys he doesn't know who is the user that use that secret, because the key is the user id hash(not the user id).

Nothing is perfect, but 2FA targets to make harder to a attacker to have success. I think it help.

ton
  • 2,505
  • 1
  • 29
  • 31
-1

I would hope that these two-factor codes are tightly time-limited (example: 5 minutes), which in my opinion is a sufficient mitigation. For example, a hacker who gets the database would only be able to use the codes for a very short period of time after he got access. Honestly, it is unlikely that he will get the first factor (the password) of any user in that time frame (assuming you do not do password hashing the wrong way), so the second factor would not even come into play in this scenario.

(This argument is independent of the point that the brute force search space for a 6-digit code is very small)

If they are not time-limited, then you should consider implementing your own timeout rather than hashing the values. Hashing is better for data that has a long-life.

TheGreatContini
  • 5,791
  • 1
  • 18
  • 25
  • The question is about the OTP *secret*, which has a long lifespan. You're talking about the generated codes. – ZachB May 12 '21 at 04:59