Currently Browsing: Home » Prevent Form Attacks with Basic Math Security

Prevent Form Attacks with Basic Math Security

Form security is a top priority these days due to the risks of losing sensitive information, getting spammed by bots, being exposed to viruses, and more. As a result, it is important to take steps to secure your forms in order to counter these risks.

Security

In this article, we’re going to create a PHP class to help secure forms with basic math questions. This class will generate two random numbers that must be added by the user in order to ensure a human is submitting the form. Taken as a whole, this class only takes about 10 minutes to write. This begs the question: are you willing to secure your forms for a few minutes of work?

View a Demo Download the Files

This PHP class, which will be called BasicMathSecurity, will have three main functions:

  • generateNumbers – generates two random numbers from 1-9 that the user must add
  • getField – returns the label and input tags that will be displayed
  • isCorrect – checks whether the user input is correct

Before we begin with these functions, let’s write a simple constructor:

public function BasicMathSecurity( $name = 'math' )
{
	$this->name = $name;
	$this->generateNumbers();
}

$name will be the name of the user input field. Note that generate numbers is called during instantiation to eliminate the need for an extra call.

generateNumbers is trivial through the use of PHP’s mt_rand function:

public function generateNumbers()
{
	$this->operand1 = mt_rand( 1, 9 );
	$this->operand2 = mt_rand( 1, 9 );
}

getField will create three HTML tags:

  • A label for the math field with the question (ex. “1 + 1 =”)
  • The math field, which is a text input
  • A hidden input field for the answer to the math question

Using the $name paramater asked for in the constructor, the following function can be produced:

public function getField()
{
	$label = '<label for="' . $this->name . '">' . $this->operand1 . ' + ' . $this->operand2 . ' = </label>';
	$math = '<input type="text" name="' . $this->name . '" value="" id="' . $this->name . '"></input>';

	$answer = '<input type="hidden" name="' . $this->name . '-answer" value="' . ( $this->operand1 + $this->operand2 ) . '"></input>';
	$string = $label . "\n" . $math . "\n" . $answer;

	return $string;
}

An id is added to the math field for styling purposes. In addition, note that the answer field uses the same name as the math field with a “-answer” appended to it. This is important for the next function.

Finally, the isCorrect function will use the global $_REQUEST array to check whether the user input matches the answer:

public function isCorrect()
{
	$answer = $this->name . '-answer';
	if( !isset( $_REQUEST[ $this->name ] ) || !isset( $_REQUEST[ $answer ] ) )
		return false;

	return (int) $_REQUEST[ $this->name ] == (int) $_REQUEST[ $answer ];
}

The $answer index is based off the code in the getField function.

As a whole, the class is as follows:

class BasicMathSecurity {

	private $name;
	private $operand1, $operand2;

	public function BasicMathSecurity( $name = 'math' )
	{
		$this->name = $name;
		$this->generateNumbers();
	}

	public function generateNumbers()
	{
		$this->operand1 = mt_rand( 1, 9 );
		$this->operand2 = mt_rand( 1, 9 );
	}

	public function getField()
	{
		$label = '<label for="' . $this->name . '">' . $this->operand1 . ' + ' . $this->operand2 . ' = </label>';
		$math = '<input type="text" name="' . $this->name . '" value="" id="' . $this->name . '"></input>';

		$answer = '<input type="hidden" name="' . $this->name . '-answer" value="' . ( $this->operand1 + $this->operand2 ) . '"></input>';
		$string = $label . "\n" . $math . "\n" . $answer;

		return $string;
	}

	public function isCorrect()
	{
		$answer = $this->name . '-answer';
		if( !isset( $_REQUEST[ $this->name ] ) || !isset( $_REQUEST[ $answer ] ) )
			return false;

		return (int) $_REQUEST[ $this->name ] == (int) $_REQUEST[ $answer ];
	}

}

To use it, construct a BasicMathSecurity object and display the field:

$math = new BasicMathSecurity( 'math' );
echo $math->getField();

Subsequently, in your form handler, check if the input is correct. Remember to construct the object with the same name parameter:

// construct the object with the same parameter
$math = new BasicMathSecurity( 'math' );
if( $math->isCorrect() ) {
	// process the form
}

And that’s it! You may view the demo and download the files used to create it.

Tags:

This entry was posted on Monday, June 14th, 2010 at 15:43:33. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

4 Responses to “Prevent Form Attacks with Basic Math Security”

  1. Lolindir Faelivrin says:

    Wov, tnx. But this isn’t the same php class you use in your spam protection?

  2. Onno Marsman says:

    It’s not really that hard to write a bot that will bypass this kind of security by evaluating the expression, I could write one myself.

    In this case it’s even simpler. Just look at the answer field and a bot has the answer, but the bot has to be aware of how this code works. Still, it’s much safer to either store the answer in a session or make a hash of the answer combined with a salt that are both passed in the form.

    A captcha like recaptcha which is also easily implemented is more spam proof though the method described is also usable by blind people and a captcha is not.

    In my experience the best way to both prevent spam and have a good user experience is to filter spam after the data is posted instead of just detecting bots, like what is possible with Akismet.

  3. Hey Onno,

    I definitely agree with you; making a bot to bypass this isn’t that hard, but nevertheless this does stop quite a lot of spam. Many bots are generalized to attack multiple sites. At the point where they are not focusing solely on your site, there’s no immediate need to bypass math security. As a result, they often times fail to do so.

    Session variables and hashing are certainly ways to improve the security. In this article, I mostly just focused on the basics. Improving the class by adding in a session variable is as simple as changing a few lines.

    In the end, helpful plugins like Akismet are great because they use a human to determine what is and what is not spam. Ultimately, this form of security may come to be the dominant way to prevent attacks, as a human’s mind is much smarter than that of a computer script (as of now… can’t tell what will happen in the future).

    Thanks for your comment. You make some great points and in turn create a useful, provocative discussion.

    Best regards,
    Karthik

  4. Hey Lolindir,

    The protection that we have on Lateral Code is actually a WordPress plugin called math comment spam protection.

    Karthik

Leave a Reply

Want to be notified when someone replies? Subscribe to this post's comment RSS feed.
Any field marked with a * is required.