0

I implemented a 2FA authentication for a web app with PHP and Google Authenticator. In order to login to my system there are a few steps:

  1. User types in a complex master password in order to access the login page. The request is throttled for only 1 request every hour and includes a CAPTCHA.

  2. User types in username and password in a web application on their computer. Forms contain CSRF token.

  3. There is a Google Recaptcha V3 to ensure the request comes from a human. This check is done in the front and backend.

  4. When the username and password matches, the server gets the secret key from the user database table and generates a QR code which is injected as a data URI src inside an HTML image tag. The user scans the bar code with google authenticator, which in turn generates a code which the user can use to login to the system.

What I don't understand: Can't anyone scan the QR-Code if they cracked the username and password? I have the feeling I'm doing something wrong in step 4.

Anyone could download the authenticator so I'm not entirely sure if its secure or is storing the secret inside my database a bad idea? Should users type in their secret to generate the QR code manually? Also, I'm thinking, shouldn't the secret change every once a while?

  • 3
    You have a login page to access the login page? Is this for you, personally, or general users? How long is your session timeout? Why limit login attempts to one every hour. That seems like a good way to DoS the account. – schroeder May 28 at 15:09
  • 3
    What are you trying to protect against? – schroeder May 28 at 15:09
  • 2
    Is this for authentication or for registration? Please tell me a user does not do this every time. If for authentication, why are you sending the code using the same channel to communicate and log in? That's not 2FA... – schroeder May 28 at 15:11
  • 2
    Why a CAPTCHA for every login? If you are only allowing one login per hour, that's a huge development overhead for no increase in protection. – schroeder May 28 at 15:18
  • 1
    This is quite confusing, you should consider all questions asked by @schroeder. It looks overcomplicated with not much reason for it. 2FA is used to mitigate password theft and brute forcing, CAPTCHA is used to avoid automated attacks and CSRF is used to avoid replay attacks. All different things meant for different purposes. Mixing them all in one bag does not get you more security. – Pedro May 28 at 15:23
2

Using a QR code in the process you described basically just ensures that the user has a cell phone, if I understand it right. So, yes, your suspicion is correct.

The way that apps like Google Authenticator are used is that the QR code is generated one time, when the account is set up (or when the user chooses to enable 2FA). The QR code is a way of sharing a secret between an app on your phone and the backend server. Once the secret has been shared with the app, the QR code is not used again (unless you need to register another app with the 2FA system and keep both apps active).

From that point on, Google Authenticator will continually generate a new temporary code every minute based on that secret. The login process will present an entry point for the temporary code. When you enter a temporary code (during the time when it is valid), it proves that you have a device that knows the secret.


While we're at it, step one is a little goofy also. For starters, I'm not sure how you would rate-limit attempts. Would you do it based on IP address? One IP address can have many users. It would be annoying if I couldn't login for the next hour because my roommate just logged in.

Beyond that, it adds one more password. A passphrase is the same factor as a password. It adds security, a little bit, but is it enough to justify memorizing something else? Why not require the password to be longer instead?

| improve this answer | |
  • Ya the idea was to block ip addresses after a number of attemps and you are also right about the pass phrase at the beginning. Thank you for your advice. – Asperger May 28 at 17:09
  • Is there any way to secure the F2A process? I could ask the user to input the secret in a form which generates the QR Code if the secret corresponds with the secret stored in the corresponding user table row. They can then scan the QR-Code. Will that make things any better in your opinion? The user would get a new secret after every succesful login. – Asperger May 28 at 17:18
  • The secret is usually generated by the server. Something super, super, super strong. I don't have details in front of me, but I would imagine something like a hundred characters, all random. Keep in mind the secret is a seed used to generate short temporary codes, so the users don't need to remember what it is or know it at all. That's all handled by the app. Theoretically, you could brute-force it, if you had unlimited access to the login system (ie, no rate-limits) and a lot of free time. A lot of free time. – Fire Quacker May 28 at 17:25
  • @Asperger "As indicated in the algorithm requirement section, keys SHOULD be chosen at random or using a cryptographically strong pseudorandom generator properly seeded with a random value... Keys SHOULD be of the length of the HMAC output to facilitate interoperability.... We also RECOMMEND storing the keys securely in the validation system, and, more specifically, encrypting them using tamper-resistant hardware encryption and exposing them only when required" - RFC 6238 – Fire Quacker May 28 at 17:38
  • Ok after reading everything I think I understand. So, say the user logs into his account. After that he could say have the option to activate 2FA. The backend creates a secret key based on HMAC and a SHA Algorithm. Key is stored in the user table row. Based on the key and issuer name, the backend generates a QR-Code. Once scanned by the authenticator app on the phone the user gets a temporary 6 digit code to login. The QR-Code cant be used again once scanned. Is my interpretation correct? 6 digits dont seem a lot, even if they change every 30 seconds. – Asperger May 28 at 18:33

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.