The time trap anti-spam technique
As a maintainer of several websites with contact forms, I’ve fought my battles with spam bots. This can easily be solved using a CAPTCHA or reCAPTCHA, but I’d rather use those options as a last resort. Honestly, CAPTCHA solutions are a personal annoyance.
This writeup outlines the time trap technique that has been very effective for regular use. By regular use, I mean the website you’re protecting isn’t big enough for a spammer to target specifically.
1. The concept
The basic concept of a time trap is very simple:
- When generating the form, the server adds a hidden form field containing a timestamp
- A spam bot fills the form automatically (usually very fast)
- The form is submitted to the server
- The server compares the timestamp in the form field against the current time
- If the time difference is beyond typing speed, it’s probably a spambot
To reduce the chance of this technique being detected, two additional measures could be taken:
- Encode the timestamp so that it’s not easily recognised as a timestamp
- Use a sensible, confusing name for the time trap field (e.g. ‘token’ instead of ‘timetrap’,’spam_protection’, …)
2. Example implementation
The concept above can be implemented in numerous ways, below is an example in Symfony to get started with:
<?php
class Contactform {
// configuration: some random number to use for encoding the time value
private $salt = 234234;
// configuration: minimum time needed to complete the form
private $minimumTime = 3; // seconds
private function createTimetrap() {
// encode the time value
return base64_encode(json_encode(time()*$this->salt));
}
private function checkTimetrap($value) {
// decode the time value
$timetrap = json_decode(base64_decode($value));
// check if the time is above the minimum time needed to complete the form
if (is_numeric($timetrap) && time() - ($timetrap/$this->salt) > $this->minimumTime) {
// it's a human
return true;
} else {
// it's a bot
return false;
}
}
}
For the minimum time, just experiment using a stopwatch and pick a reasonable time for a human to fill in the form.
3. Back-up plan
Let’s assume a super fast human fills in your form. You want to give him/her some contact option in this case:
<?php
if(!$this->checkTimetrap($data['time'])) {
die("Aborting due to spam detection. Please use our chat widget to get in touch.");
}
And that’s it!