ASVS 5.0 V6.5.8 requires that time based one time passwords are validated against a time source from a trusted service, not a time value supplied by the client. It is a Level 3 requirement.
Why it matters
A TOTP is a function of a secret and the current time. If the verifier accepts a timestamp from the request, an attacker who captured one valid code can claim it was generated at that timestamp and replay it forever. Even without a request field, a server with a wrong or manipulable clock widens the window.
How to implement it
Take time from the server, and keep the server clock disciplined.
import time, pyotp
def verify(user, code):
totp = pyotp.TOTP(user.seed)
# valid_window=1 allows one 30 second step of drift each way
return totp.verify(code, for_time=time.time(), valid_window=1)
Never read timestamp, time or ts from the client for this check. Operationally:
- Synchronize servers with a trusted NTP source, ideally several, and alert on drift.
- Use the same source across all verification nodes.
- Log the matched time step and combine with single use (V6.5.1).
How to test it
- Send a code with an extra timestamp parameter. It must be ignored.
- In a test environment, skew the server clock by a few minutes and confirm valid codes fail, then restore it.
- Check monitoring for NTP sync status.
Common mistakes
- Passing a client time to the verifier for "offline mode".
- Servers with unsynchronised clocks.
- Large drift windows to hide clock problems.
Quick check
Why not let the client send its own time to fix drift?
It lets an attacker choose the time, so a captured code stays valid indefinitely.