RobThree / TwoFactorAuth

PHP library for Two Factor Authentication (TFA / 2FA)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Why key can validate multiple use ?

parnus01 opened this issue · comments

when i validate key and success login , after i logout why it can use same key to validate

How can i implement it to expire key now after validate success.

thnak you

when i validate key and success login , after i logout why it can use same key to validate

Uh.. thats how TOTP works... TOTP is a time-based code. Each code is valid for a certain period (usually a 'window' of 30 seconds +/- 1 (or more periods either way) so in effect each code is (by default) valid for ~90 seconds.

... For this to work, the clocks of the user's device and the server need to be roughly synchronized (the server will typically accept one-time passwords generated from timestamps that differ by ±1 time interval from the client's timestamp). A single secret key, to be used for all subsequent authentication sessions, must have been shared between the server and the user's device over a secure channel ahead of time. If some more steps are carried out, the user can also authenticate the server using TOTP. (Source)

The period length (30 seconds) and number of intervals ("time-slices") may differ and can both be set ($period in the constructor and $discrepancy in the verifyCode() method). But not all "authenticator apps" support periods other than 30 (or multiples of) seconds.

How can i implement it to expire key now after validate success.

Codes "expire" every (in the example above) 90 seconds (with a period of 30 s and T±1 interval). If you want to prevent a replay-attack (or "expire" a code immediately) you should store the last "login timeslice" (UNIXTIME modulo period) and disallow new logins in that same timeslice±X intervals. How to do that; that's up to you. You could store it in a database, file, whatever... I would store it in the same place as the user is stored (e.g. in the same "user record" as lastsuccessfullogintime or something).

Besides replay-attacks you can also 'brute force' a TOTP code so you should also rate-limit the number of allowed login attempts before locking out an account for a certain amount.

There is more info on possible attacks here. In the 4 attack vectors named in that document I can give you the following advice:

Attack Solution
Replay attack Store last login time as suggested above
Brute force attack Rate limit number of attempts
Phone stealing attack
  • ...don't loose your phone
  • Password protect your phone with a decent password / fingerprint
QR Code stealing
  • Cache problem is (partially¹) circumvented because we use a data-uri
  • Implement a QR code provider so you don't need to rely on third parties and: use SSL!²
  • If you don't implement your own QR code provider; the QR code is requested and generated server-side to 3rd party; MiTM or capturing HTTP requests will be hard (if implemented correctly and as instructed in the README no extra (client-side) requests are done at all) unless the connection between your server and third party is compromised (instead of the connection between client and sever). Use SSL² for 3rd party & client!
  • Use SSL!
  • Use SSL!
  • Use SSL!
¹ You will want to send HTTP no-cache headers for the page serving the QR-code though

² MitM between client & server is at any time possible but SSL will make it (much) harder

There are more attack vectors not mentioned in the aforementioned presentation (side-channel attacks like timing attack, weak RNG etc.) but TwoFactorAuth mitigates those already.

More info that may be relevant for you:

ok,i understand and How i can reduce time to expire (90 seconds) to 30 or 60 ?

iam try to chage $discrepancy it not work

How i can reduce time to expire (90 seconds) to 30 or 60 ?

Please read the README and above explanation. You can use $period and $discrepancy and both work exactly as documented.

iam try to chage $discrepancy it not work

Please tell me how to reproduce (i.e. what you did/do exactly, what "not work" means). Are you sure you're implementing it correctly and have understood how this all works? Opening an issue and complaining "iam try to chage $discrepancy it not work" after an (extended!) explanation of what is, essentially, also in the README is not the way to go; please show a little more effort on your behalf. You could start with telling me to what value you changed $discrepancy and how you went from there.

i just change $discrepancy = -4 but it same90 seconds

i just change $discrepancy = -4 but it same90 seconds

What made you think a $discrepancy of -4 would work?
The smallest discrepancy is 0. If anything, this library should throw on negative discrepancies...

The $discrepancy argument is the number of timeslices checked by verifyCode (to either side of T where T is the current timeslice). So:

$discrepancy Checked (or "valid") timeslices Validity (for $period = 30)
0 T 30 seconds
1 (default) T-1, T, T+1 90 seconds
2 T-2, T-1, T, T+1, T+2 150 seconds
3 T-3, T-2, T-1, T, T+1, T+2, T+3 210 seconds
...etc... ...etc... ...etc...

Above is with a (default) $period of 30; if we change it to, say, 10 the result would be:

$discrepancy Checked (or "valid") timeslices Validity (for $period = 10)
0 T 10 seconds
1 (default) T-1, T, T+1 30 seconds
2 T-2, T-1, T, T+1, T+2 50 seconds
3 T-3, T-2, T-1, T, T+1, T+2, T+3 70 seconds
...etc... ...etc... ...etc...

A discrepancy of -4 checks no timeslices (see for yourself) and should always return false for verifyCode(). So I don't know why you come to the conclusion "but it same90 seconds"?

The README explains all of this pretty clear in step 2?

You need to realize that you want to allow for some time-difference between server and user's device. The lower the threshold, the more exact time you require your users to keep. Lowering the $discrepancy and $period is not the solution to your original problem I think.

As I commented earlier you're better of storing the last succesful login. And keep in mind that the other measures I mentioned in that comment (rate-limiting, SSL etc.) should also be implemented if you want to be safe.

ok if iwant 30 to expire set $discrepancy=0 and not concern $peroid ?

ok if iwant 30 to expire set $discrepancy=0 and not concern $peroid ?

Your question is unclear but from what I understand from it I'm pretty sure the answer is yes, pass 0 to the $discrepancy argument and keep $period default (or set it explicitly to 30). Again; this should be clear if you read the README (and/or my earlier posts in this thread).

Could you explain why you would want such tight restrictions? It doesn't really make things 'safer' or anything; the only thing it does do is frustrate your users whenever their time is off a little.