Quick Form CAPTCHA Using Math Problem

Published on 5th Feb, 2015

CAPTCHA is a delicate balance.

On the one hand you want your forms to be secure from erroneous submissions, on the other hand you don't want to annoy your users with garbled security-images or poorly recorded sound bytes. I personally seem to have no gift for typing in the characters from an image that looks as though it's been drawn in MS Paint by a four year old and then treated to a healthy sneeze from said child.

My favorite way to prove my humanity, is with a simple math problem.


This is very easy to answer and very easy to see. But how would one safely implement this on a form? Some folks just hard-code the same math problem in every form. Which works well for many cases, but if an attacker takes the time to look on your site, they could modify their scripts to include the correct answer.

So I came up with a slightly better option:

// FormPage.html.php
$mathArray = array(
    array(
        "label" => "4 + 6 = ",
        "answer" => 10
    ),
    array(
        "label" => "2 + 4 = ",
        "answer" => 6
    ),
    array(
        "label" => "3 + 8 = ",
        "answer" => 11
    ),
    array(
        "label" => "10 - 3 = ",
        "answer" => 7
    )
);
$mathIndex = array_rand($mathArray, 1);
$mathLabel = $mathArray['mathIndex'];

Now you can echo the label variable into your field label, and create a hidden form element with a value set to $mathIndex. Then on the receiving side of your application you can paste the same array and check like so:

// receive.php
$mathArray = array(
    array(
        "label" => "4 + 6 = ",
        "answer" => 10
    ),
    array(
        "label" => "2 + 4 = ",
        "answer" => 6
    ),
    array(
        "label" => "3 + 8 = ",
        "answer" => 11
    ),
    array(
        "label" => "10 - 3 = ",
        "answer" => 7
    )
);

$answer = $_POST['math_question'];
$questionIndex = $_POST['math_index'];

if($mathArray[$questionIndex]['value'] != $answer){
    //Fail CAPTCHA
}

Easy as that. You can make the array of questions as long as you want and if you want to secure it even more, just call:

shuffle($mathArray);

That way your indexes are never the same, though if you do this, you'll need to store the order somewhere for the receiving end of the form. Plopping it in a database or a server-side JSON file might be manageable, but I think that it's unnecessary as the question will be different on most every page load.

The above is a bare-bones implementation. It might be better to, rather than write out the array's, place the questions into a database (MySQL, JSON, SQLite, etc) and query the questions out as needed. Regardless, I think this is a simple way to approach CAPTCHA.

Hit me up with any questions/suggestions.

-Richard Cagle

This article is my 24th oldest. It is 471 words long

comments powered by Disqus