turnley.dev

PHP and MySQL code for faucet operators

Tools & Calculators

FRD-009

Enforce a minimum dwell that a script cannot skip

The countdown belongs to the client, so the client will lie. Bind the timing to a signed server token and check it when the claim arrives.

Timers on surf pages, PTC offers and interstitials all have the same weakness: the code that decides the timer finished runs on the visitor's machine. Anyone can post the completion form early.

Move the decision to the server. When the page is served, issue a signed token carrying the time it was issued. When the completion arrives, verify the signature and check the clock yourself. The countdown on screen becomes what it always was — a display — and the enforcement lives somewhere the visitor cannot reach.

Add an upper bound as well. A token accepted an hour later is a token that was harvested and replayed.

PHP
function issue_dwell_token(int $itemId, string $visitorKey): string
{
    $payload = $itemId . '|' . $visitorKey . '|' . time();
    return base64_encode($payload . '|' . hash_hmac('sha256', $payload, HMAC_SECRET));
}

function check_dwell_token(string $token, string $visitorKey, int $minSeconds, int $maxSeconds = 1800): ?int
{
    $raw = base64_decode($token, true);
    if ($raw === false) {
        return null;
    }
    $parts = explode('|', $raw);
    if (count($parts) !== 4) {
        return null;
    }
    [$itemId, $boundKey, $issuedAt, $sig] = $parts;

    $expected = hash_hmac('sha256', $itemId . '|' . $boundKey . '|' . $issuedAt, HMAC_SECRET);
    if (!hash_equals($expected, $sig) || !hash_equals($boundKey, $visitorKey)) {
        return null;
    }

    $elapsed = time() - (int) $issuedAt;
    if ($elapsed < $minSeconds) {
        return null;                       // too fast: the timer was skipped
    }
    if ($elapsed > $maxSeconds) {
        return null;                       // too old: harvested and replayed
    }

    return (int) $itemId;
}

Using it

Give a second or two of grace below the nominal timer. Network latency and a slow render otherwise fail honest visitors right at the boundary.

Record used tokens for the length of the maximum window so the same one cannot be posted twice.

What bites people

Do not put the required duration inside the token. Read it from your own settings at check time, or a visitor can hand you a token that says it only needed one second.

Server clock changes invalidate every token in flight. Worth knowing before you blame the code.

This one touches real money. Point it at a throwaway wallet and watch a full cycle before you trust it with a live balance.

Also in Anti-Bot and Fraud