Last Updated:

Protect Web Forms from Automatic Processing [PHP]

The article describes a way to implement a mechanism that allows you to combat automatic filling of forms, false registrations and spam through the feedback form.

Requirements: PHP>=4.0.6, GD >=2.0.

This article is based on nathan Rohler's article "Security Images in PHP" published on #Dev Shed on August 9, 2004. In general, from the beginning, I was visited by the idea of its translation, but, firstly, the author chose an interesting, but not the most trivial version of the solution to the problem, and secondly, I would hardly be able to formulate such an abundance of thoughts in Russian language.

Recently, due to the spreading spam epidemic, webmasters began to hide their e-mail addresses more and more often. Many began to use feedback forms. But as it turned out, such protection can be circumvented. And already today, there are a huge number of programs designed to send spam, through feedback forms.

Our task is to make sure that only a "living person" can send a message to you. Most often, small pictures are used for this, on which text is displayed. The user is asked to duplicate this text in the input field. If the duplication is incorrect, the form is not processed.

To date, I am not familiar with any program that can bypass such protection. I don't even know of any program that tries to recognize the contents of a picture. For this reason, we can safely say that today there is no need to somehow distort the image in the picture. But we are looking to the future.

Image Generation

The author proposed the following algorithm: a complex image in the picture is formed using pre-prepared substrates. After that, text is displayed on the substrates, random font, random size and, of course, random content.

The main drawback of such an algorithm is that the existing "substrate" can be quickly calculated. And then subtract from the image that you need to recognize and thus get a picture with clean text. And to recognize such a text, there are already a lot of programs today.

Our task is to make an absolutely random substrate, with a text that is not only difficult to recognize, it is difficult to read.

I would suggest the following algorithm:

  1. Create a substrate (for this you can use the algorithm for constructing fractals)
  2. Add interference - a few random lines, the colors of the main text.
  3. Display the main text
  4. The most interesting thing is to enlarge the image an uneven number of times - for example, in 1.7, in 1.6
  5. Reduce the image to its original dimensions

It is necessary to increase and decrease the image using anti-aliasing, otherwise even a person will not be able to read the text.

If you think that drawing a fractal is too difficult, then you can draw a simple grid.

How the mechanism works

When a user enters the page with the form, we create a session and write random code to the registered variable:

 
Code:
 
session_start();
session_register("secret_number");

if (intval($_SESSION["secret_number"])<1000) {
srand(doubleval(microtime()));
$_SESSION["secret_number"]=rand(1000,9999
);
    }
 
 

After the random text is generated, you need to display the form:

 
 
Code:
 
<form action="index.php" method="post">
Your E-Mail:<br>
<input type="text" name="email" value="><br>
<br>
Enter the code you see in the picture:<br>
<input type="text" name="secretcode" value="><br>
<img src='code.php?<?=doubleval(microtime());? >'
width=101 height=26 vspace=5>
<br><br>
<input type="submit">
</form>
 

A script that processes data submitted by using a form should work similarly to the following:

 
 
Code:
 
session_start();
session_register("secret_number");

if ($_SERVER["REQUEST_METHOD"]=="POST") {

$error=0;
if ($_POST["secretcode"]!=$_SESSION["secret_number"] ||
intval($_POST["secretcode"])==0) $error=1;

if ($error==0) {
$_SESSION["secret_number"]=rand(1000,9999);

Perform the necessary actions with the
data ..
print "Hello ". htmlspecialchars(StripSlashes($_POST["email"]));
exit;
}

if ($error==1)
print "<font color=red>The number from the picture was entered incorrectly</font>";
}
 

Display the form again
...

Image Generation

 
Code:
 
<?
Register the variable
session_start();
session_register("secret_number");

function mt() {
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}

header("Content-type: image/png");

create an image
$im=imagecreate(101, 26);

Highlight the background color (white)
$w=imagecolorallocate($im, 255, 255, 255);

Highlight the background color (light gray)
$g 1=imagecolorallocate($im, 192, 192, 192);

Highlight the color for darker interference (dark gray)
$g 2=imagecolorallocate($im, 64,64,64);

Select four random dark colors for $cl
1=imagecolorallocate($im,rand(0,128),rand(0,128) ,rand(0,128));
$cl2=imagecolorallocate($im,rand(0,128),rand(0,128),rand(0,128 ));
$cl3=imagecolorallocate($im,rand(0,128),rand(0,128),rand(0,128));
$cl4=imagecolorallocate($im,rand(0,128),rand(0,128),rand(0,128 ));

Draw a grid
for ($i=0; $i<=100; $i+=5) imageline($im,$i,0,$i,25,$g1);
for ($i=0; $i<=25; $i+=5) imageline($im,0,$i,100,$i,$g1);

Display each digit separately, slightly shifting imagestring
($im, 5, 0+rand(0,10), 5+rand( -5,5),
substr($_SESSION["secret_number"],0,1), $cl1);
imagestring($im, 5, 25+rand(-10,10), 5+rand(-5,5),
substr($_SESSION["secret_number"],1,1), $cl2);
imagestring($im, 5, 50+rand(-10,10), 5+rand(-5,5),
substr( $_SESSION["secret_number"],2,1), $cl3);
imagestring($im, 5, 75+rand(-10,10), 5+rand(-5,5),
substr($_SESSION["secret_number"],3,1), $cl4);

Display a couple of random lines of close color, right on top of the symbols.
To increase the number of lines,
you can increase the number highlighted in
red for ($i=0; $i<8; $i++)
imageline($im,rand(0,100),rand(0,25),rand(0,100 ),rand(0,25),$g2);


The coefficient of increase/ decrease of the
picture $k = 1.7;

Create a new image, larger $im
1=imagecreatetruecolor(101*$k,26*$k);

Copy an image with a large resizing imagecopyresized($im 1, $im, 0, 0, 0, 0, 101*$k, 26*$k, 101, 26);

Create a new image, normal size
$im 2=imagecreatetruecolor(101,26);

Copy an image with a smaller
dimension imagecopyresampled($im 2, $im 1, 0, 0, 0, 0, 101, 26, 101 *$k, 26*$k);

Generate
imagepng($im 2);

Free the memory
imagedestroy($im 2);
imagedestroy($im1);
imagedestroy($im);
?>
 

Like everything. If anything, leave comments.