Getting spam despite Securimage captcha - how to fix?

72 views Asked by At

Last year, I began building a website for an organisation. It contains a contact form implemented in PHP, with a Securimage captcha.

Today I checked the database table into which contact messages are archived, and discovered it to be full of spam! The spams started in August 2022, about a month after the contact form was put live, and the rate of spams peaked in August-September at 11 per day. Now they're one every 1-2 days, which is still a far cry from the level that having a captcha is meant to get it down to. Going by the recent logs, it doesn't seem to be a brute-force attack or anything like that.

The code to render the contact form is like this:

<form method="post" action="contact">
    <div class="tabForm">
    <?php
        renderInlineField('name', 'Your name:');
        renderInlineField('email', 'Email address:');
        renderInlineField('subject', 'Subject:');
    ?>
        <p><?php renderLabel('message', 'Message:'); ?> <textarea style="width: 100%; height: 15em;" name="message" id="message"><?php echo htmlspecialchars($message); ?></textarea></p>
        <p><img id="captcha" src="securimage/securimage_show.php" alt="[CAPTCHA Image]" /></p>
        <p><audio id="captcha_one_audio" preload="none" controls="controls">
            <source id="captcha_one_source_wav" src="securimage/securimage_play.php?id=<?php echo uniqid(); ?>" type="audio/wav" />
        </audio></p>
        <p><?php renderLabel('captcha', 'Please enter the characters you see/hear:'); ?> <input type="text" name="captcha" id="captcha" size="10" maxlength="6" /></p>
        <p><input type="submit" value="Submit" /></p>
    </div>
</form>

The two functions (besides uniqid) are defined as follows:

function renderInlineField($fieldName, $htmlLabel) {
    global $errors;
    echo "<p class='inline'>";
    renderLabel($fieldName, $htmlLabel);
    echo "<input type='text' name='$fieldName' id='$fieldName' maxlength='255' value='", htmlspecialchars(@$_POST[$fieldName]), "' /></p>";
}

function renderLabel($fieldName, $htmlLabel) {
    global $errors;
    echo "<label for='$fieldName'>";
    if (!empty($errors[$fieldName])) echo "<span class='error'>($errors[$fieldName])</span> ";
    echo "$htmlLabel</label>";
}

The code that verifies the captcha:

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $name = sanitise($_POST['name']);
    $email = trim($_POST['email']);
    $subject = sanitise($_POST['subject']);
    $message = trim($_POST['message']);
    $captcha = $_POST['captcha'];
    
    $errors = [];
    
    session_start();
    require_once 'securimage/securimage.php';
    $securimage = new Securimage();

    if (empty($name)) $errors['name'] = 'missing';
    
    if (empty($email)) {
        $errors['email'] = 'missing';
    } else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors['email'] = 'not valid';
    }
    if (empty($message)) $errors['message'] = 'missing';
    
    if (empty($captcha)) {
        $errors['captcha'] = 'missing';
    } else if (!$securimage->check($captcha)) {
        $errors['captcha'] = 'not entered correctly';
    }
    
    if (empty($errors)) {
        // code to store the message in the database and email it to the intended recipient
    }
}

My questions are:

  • Can anyone see any holes in this code which a spambot would be able to exploit?
  • Has anyone found a solution that works?
0

There are 0 answers