heapsource / active_model_otp

Adds methods to set and authenticate against one time passwords (Two-Factor Authentication). Inspired in AM::SecurePassword
MIT License
773 stars 81 forks source link

Preventing reuse of Time based OTP's? #39

Closed MohdAnas closed 3 years ago

MohdAnas commented 7 years ago

Is it possible to prevent reuse of time bases OTP's by using this library?

pgouv commented 6 years ago

Isnt this what you want ? https://github.com/heapsource/active_model_otp#counter-based-otp

domcleal commented 6 years ago

Counter based is HOTP, rather than TOTP, so it's quite different. It ought to be possible to prevent a TOTP value from being re-used without switching methods.

rotp 3.2+ has a verify_with_drift_and_prior option (or after in the v4.0 branch), where if you supply a last login time (e.g. from devise), it'll fail TOTP verification for old codes. (Added in https://github.com/mdp/rotp/pull/58.)

Perhaps a prior option given by the user to authenticate_otp could be passed through to this method?

KOrnelB commented 3 years ago

By keeping track of the last time a user's OTP was verified, we can prevent token reuse during the interval window (default 30 seconds)

The following is an example of this in action:

user = User.find(someUserID) totp = ROTP::TOTP.new(user.otp_secret) totp.now # => "492039"

Let's take a look at the last time the user authenticated with an OTP

user.last_otp_at # => 1432703530

Verify the OTP

last_otp_at = totp.verify("492039", after: user.last_otp_at) #=> 1472145760

ROTP returns the timestamp(int) of the current period

Store this on the user's account

user.update(last_otp_at: last_otp_at)

Someone attempts to reuse the OTP inside the 30s window

last_otp_at = totp.verify("492039", after: user.last_otp_at) #=> nil

It fails to verify because we are still in the same 30s interval window

This should be implemented ...

pedrofurtado commented 3 years ago

I think this workaround provided above can help someway 🤝 Feel free to reopen, to provide more details, if needed 👍