ASVS 5.0 V2.4.2 requires that business logic flows demand realistic human timing, preventing excessively rapid transaction submissions. It is a Level 3 requirement.
Why it matters
A bot completes a ten field form in 80 milliseconds. A person cannot. Timing is a cheap signal for sign up abuse, ticket scalping and credential stuffing that sits alongside rate limits.
How to implement it
Record on the server when a flow step was served, and check the elapsed time on submission. Do not trust a timestamp sent by the client.
MIN_SECONDS = 3
def on_submit(session):
elapsed = time.time() - session["step_served_at"]
if elapsed < MIN_SECONDS:
raise TooFast() # return 429 and ask to retry
Choose the minimum per step from real data, for example the fifth percentile of genuine users. Keep it as a signal, not an absolute ban: slow the response or add verification instead of locking out autofill users and people with assistive tools.
How to test it
Submit each protected form with a script immediately after loading it and confirm rejection. Then complete it at normal speed and with a password manager to confirm real users pass.
Adding variety
Combine timing with other cheap signals: whether the form was loaded at all, whether the same session submits many forms quickly, and whether input arrives with no focus or keyboard events when your front end can observe them. None is conclusive. Together they let you step up verification only for suspicious sessions.
Common mistakes
- Reading the start time from a hidden field.
- Setting a limit so strict that autofill fails.
Quick check
Does a timing check replace rate limiting?
No. It is one more layer. Patient bots can wait, so keep rate limits and other controls.