[Defending Aganist Spambots - Form Expirations](/content/blog/defending-aganist-spambots-form-expirations "View Defending Aganist Spambots - Form Expirations"/index.html)
By: Anthony Green 08/17/2016

Humans are inherently slower than computers when it comes to reading and filling out a form. Even simple login forms where everything is auto-completed and you just have to click the “login” button takes a second, while a computer can do it in milliseconds. More complex forms require even more time to for a human to read, understand and complete. Recoding the timestamp of the form request and requiring the response to occur with a set range makes the automatic completion of the form more expensive for a spambot.

The timestamp can be sent along with the normal form fields as a hidden input field, so long as the validity of the timestamp is checked when validating the form submission. The easiest method is a HMAC check with a server-specific key. This actually allows for integration of additional data into the timestamp field, like the requester’s IP address and User agent.

Example Creation and Validation of a Form Timestamp

// globals
$gvServerPublicFormKey = '5f4dcc3b5aa765d61d8327deb882cf99';

//! Create Timestamp Field
//! @return string HTML of timestamp field
function createTimestampField(){
    global $gvServerPublicFormKey;

// get current unix timestamp
    $t = time();

// compose raw value as time:IP:user agent
    $data = $t . ':' . $_SERVER['REMOTE_ADDR'] . ':' . $_SERVER['HTTP_USER_AGENT'];

// generate HMAC hash
    $hash = hash_hmac('sha512', $data, $gvServerPublicFormKey);

// build input
    $html = "";

return $html;
}

//! Validate Timestamp Input
//! @param int $min Minimum delay time in seconds @default[5]
//! @param int $max Maximum delay time in seconds @default[1200]
//! @returns bool Returns the validity of the timestamp input field
function validateTimestampInput($min = 5, $max = 1200) {
    global $gvServerPublicFormKey;

$t = 0;
    $hash = '';

// field field
    foreach($_REQUEST as $key => $val) {
        if(strpos($key, 'ts-') !== 0) continue;

$t = substr($key, 3);

// validate potential timestamp value
        if(!$t || intval($t) != $t || $t + $min < time() || $t +$max > time()) {
            continue;
        }

$hash = $val;
        break;
    }

// potentially valid timestamp not found
    if(!$hash) return FALSE;

// generate hash based upon timestamp value
    $data = $t . ':' . $_SERVER['REMOTE_ADDR'] . ':' . $_SERVER['HTTP_USER_AGENT'];
    $correctHash = hash_hmac('sha512', $data, $gvServerPublicFormKey);

// return validity of hmac hash
    return hash_equals($hash, $correctHash);
}