Security Tip: Don't Forget to Regenerate 2FA Secret Keys!

[Tip #84] It's not just passwords you need to worry about when it comes to authentication and stolen credentials: your 2FA secret keys may also be at risk!

Security Tip: Don't Forget to Regenerate 2FA Secret Keys!

A common mistake when implementing Time-based One-Time Password (TOTP) Two-Factor Authentication (2FA) is to generate the user's secret key once, and then reuse the same secret key even when TOTP is disabled and enabled, providing the user with no mechanism to reset their key.

This opens up a similar risk to password reuse: if an attacker can obtain the user's secret key, and the user has no way to reset it, then the attacker just needs the user's password to successfully log in! (As they will always have a valid TOTP!) 😱

But, why is this an issue, and how can an attacker obtain the user's secret key?

While it is unlikely, it's not unheard of for 2FA secret keys to be leaked in some way - such as with the Spoutible data breach, but also consider if the user's device is compromised: an attacker could access the user's authenticator app and steal their secret keys - the user would need to reset their passwords and TOTP keys ASAP!

The solution is simple: wipe the secret key when TOTP is disabled, and generate a fresh key when TOTP is enabled.

This will ensure a fresh key any time TOTP is toggled, and provide a logical reset method if the user needs to reset their key.

Laravel Fortify (the backend for Jetstream) does this with it's EnableTwoFactorAuthentication and DisableTwoFactorAuthentication actions.

P.s. I'd also suggest encrypting your 2FA secret key in the database, for added security in case of a data breach!

2FA - Two-Factor Authentication
MFA - Multi-Factor Authentication
2SV - Two-Step Verification

These are all similar terms with subtle differences that relate to authenticating users with multiple authentication factors: something you know (passwords), something you have (physical device), something you are (biometrics).

TOTP - Time-based One-Time Password

A cryptographically secure method of generating a unique code every 30 seconds, to provide something you have, in the form of a physical device - i.e. your phone.

Today's security tip was an issue I discovered during a recent Laravel Security Audit and Penetration Test. Although it would be fairly difficult to exploit in the wild, it still poses a significant risk if the conditions were met - especially in a targeted attack, so it's something you should definitely check in your own apps. The fix is also fairly simple, so you've got no excuse...

If you've made it this far, please consider sharing this security tip (and Securing Laravel in general) with your Laravel friends and colleagues. The more folks learning about security and writing secure code, the safer we'll all be!