Simpele CAPTCHA beveiliging
Ik vond een stukje code (van ene Julien Pachet) op het web, waarmee je zonder de GD toestanden een plaatje kunt genereren met een code, die posters van een form moeten invullen. Ik heb er nogal wat aan zitten sleutelen voordat het naar m'n zin was en ik vind het prima zo. For the time beeing althans, want het schijnt absoluut geen lekvrije beveiliging te zijn. Het houdt de n00bs en de snotapen buiten de deur, maar als iemand er écht voor gaat zitten, dan komt zijn bot er wel door, denk ik. Het is zo simpel als wat. Het zijn 2 bestanden: "class_ocr_captcha.inc.php", die je include in je form "example.php", plus een (zelf uit te kiezen) fontbestand. In de class kun je wijzigingen aanbrengen (pad+naam fontbestand, hoogte/breedte van het plaatje, de hoeveelheid noise, etc.) In het voorbeeld wordt, als de gebruiker een foutieve code intypt, niet de hele pagina weergegeven, maar alléén het form. Zelf vind ik het namelijk lastig als ik naar beneden moet scrollen om te zien of alles goed is gepost. Bestand captcha.zip is te downloaden via het voorbeeld.
[code]
<?php // example.php: het formulier ?>
<?php
session_start();
ob_start();
require_once("./class_ocr_captcha.inc.php");
$p = new ocr_captcha();
// initaliseren
$gepost = false;
$errmsg = "";
$btncap = "Verzenden";
if (!($text1)) $text1 = "Dit is veld 1";
if (!($text2)) $text2 = "Dit is veld 2";
// is het form gepost?
if (isset($_POST['public_key'])) {
$public = $_POST['public_key'];
}
if (isset($_POST['private_key'])) {
$gepost = true;
$private = $_POST['private_key'];
$codeOK = ($p->check_captcha($public,$private));
// is de ingetypte code juist?
if (!($codeOK)) {
// error vars
$errmsg = "FOUT! FOUT! FOUT!"; // foutboodschap
$btncap = "Ik probeer het nog een keer"; // button caption <bg>
}
} // end if (form gepost)
?>
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>
<html>
<head><title>Captcha test</title></head>
<body style="margin-left:50px;">
<?php
// if (niet gepost) OF (code onjuist) dan het form (opnieuw) tonen
if (!($gepost) || !($codeOK)) { ?>
<form name="frm" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<table width="50%" border="0" cellspacing="0" cellpadding="15">
<?php // if (niet gepost) dan de volledige pagina tonen
if (!($gepost)) {
// display alle tekst ?>
<tr><td bgcolor="#CCFFFF">TEKST PAGINA
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
</td></tr>
<tr><td width="70%"> </td></tr>
<?php } // end if (niet gepost) ?>
<tr><td bgcolor="#FFFF99">TEKST FORM
<p>Uitleg over het form. Andere teksten voor het form.</p>
</td></tr>
<tr><td bgcolor="#FFFF99">
Veld 1<br>
<input name="text1" type="text" id="text" value="<?php echo $text1; ?>" size="40" />
</td></tr>
<tr><td bgcolor="#FFFF99">
Veld 2<br>
<textarea name="text2" cols="30" rows="10"><?php echo $text2; ?></textarea>
</td></tr>
<tr>
<td valign="bottom" bgcolor="#FFFF99">
<font style="font-size:small">Type deze code van <?php echo $p->long; ?> tekens in het veld hieronder</font><br />
<?php echo $p->display_captcha(true); // toon plaatje met de code ?>
<input type="text" name="private_key" value="" maxlength="6" size="6"
style="height:25px;font-size:22px;font-weight:bold;text-transform:uppercase;" />
<?php echo $errmsg; // foutboodschap of lege string ?>
<?php $private=$p->generate_private(); // private key genereren ?>
</td>
</tr>
<tr>
<td bgcolor="#FFFF99">
<input name="btnSend" type="submit" value="<?php echo $btncap; ?>" />
</td>
</tr>
</table>
</form>
<?php
} else {
// alles ok. inserten.
echo "in de database ermee!<br><br>";
echo "Veld 1: $text1<br>";
echo "Veld 2: $text2<br><br>";
echo "Dank u wel alstublieft.";
} // end if (niet gepost) OF (code onjuist)
?>
</body>
</html>
//////////////////////////////////////////////////////////
<?php // class_ocr_captcha.inc.php: de class ?>
<?php
/////////////////////////////////////////////////////////
// CLASS NAME: OCR_CAPTCHA
// FILE NAME : CLASS_SESSION.INC.PHP
// LANGUAGE : PHP
// AUTHOR : Julien PACHET
// EMAIL : j|u|l|i|e|n| [@] |p|a|c|h|e|t.c|o|m
// VERSION : 1.0
// CREATION : 17/03/2004
// LICENCE : GNU GPL
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
// What the class does: //
////////////////////////////////////////////////////////
// * Make a catcha picture (Completely Automated Public Turing to tell Computers from Humans Apart)
// To test if a human is really behind the web page. In a form, you put a captcha picture, and a text
// Field, and then...
// * Check if the text typed in the field from the picture (private key) corrrespond to the public_key
// that the class inserted in a hidden field //
// Indeed, the class can prevent from automatic (bot) filling form for example: //
// _ poll
// _ account creation
// _ account loggin (prevent from brute force password tries //
// _ check for access to a given page (to stop bot like search bot or spam bot //
// _ ...
// More infos at http://www.captcha.net //
///////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// Need to work:
/////////////////////////////////////////////////////
// other files: none
// other datas: a private string (see in file class) use to make private key from public key
/////////////////////////////////////////////////////
class ocr_captcha {
var $key; // ultra private static text
var $long; // size of text
var $lx; // width of picture
var $ly; // height of picture
var $nb_noise; // nb of background noisy characters
var $filename; // file of captcha picture stored on disk
var $imagetype="png"; // can also be "jpg";
var $public_key; // public key
var $font_file = "./arialbd.ttf"; // <------------- hier de bestandsnaam van het font
function ocr_captcha($long=5,$lx=120,$ly=30,$nb_noise=5) {
$this->key=md5("A nicely little text to stay private and use for generate private key");
$this->long=$long;
$this->lx=$lx;
$this->ly=$ly;
$this->nb_noise=$nb_noise;
$this->public_key=substr(md5(uniqid(rand(),true)),0,$this->long); // generate public key with entropy
}
function get_filename($public="") {
if ($public=="")
$public=$this->public_key;
if (!is_dir("tmp")) // test if rep exist
mkdir("tmp");
if (strpos($_SERVER['SystemRoot'], ":\\")===false) // so linux system
$rad="tmp/"; // Document_root works nicely here
else // windows system
$rad="tmp\\";
return $rad.$public.".".$this->imagetype;
}
// generate the private text coming from the public text, using $this->key (not to be public!!), all you have to do is here to change the algorithm
function generate_private($public="") {
if ($public=="")
$public=$this->public_key;
return substr(md5($this->key.$public),16-$this->long/2,$this->long);
}
// check if the public text is link to the private text
function check_captcha($public,$private) {
// when check, destroy picture on disk
if (file_exists($this->get_filename($public)))
unlink($this->get_filename($public));
return (strtolower($private)==strtolower($this->generate_private($public)));
}
// display a captcha picture with private text and return the public text
function make_captcha($noise=true) {
$private_key = $this->generate_private();
$image = imagecreatetruecolor($this->lx,$this->ly);
$back=ImageColorAllocate($image,intval(rand(224,255)),intval(rand(224,255)),intval(rand(224,255)));
ImageFilledRectangle($image,0,0,$this->lx,$this->ly,$back);
if ($noise) { // rand characters in background with random position, angle, color
for ($i=0;$i<$this->nb_noise;$i++) {
$size=intval(rand(6,10)); // grootte van de noise
$angle=intval(rand(0,360)); // hoek van de noise
$x=intval(rand(10,$this->lx-10));
$y=intval(rand(0,$this->ly-5));
$color=imagecolorallocate($image,intval(rand(160,224)),intval(rand(160,224)),intval(rand(160,224)));
$text=chr(intval(rand(45,250)));
ImageTTFText ($image,$size,$angle,$x,$y,$color,$this->font_file,$text);
}
}
else { // random grid color
for ($i=0;$i<$this->lx;$i+=10) {
$color=imagecolorallocate($image,intval(rand(160,224)),intval(rand(160,224)),intval(rand(160,224)));
imageline($image,$i,0,$i,$this->ly,$color);
}
for ($i=0;$i<$this->ly;$i+=10) {
$color=imagecolorallocate($image,intval(rand(160,224)),intval(rand(160,224)),intval(rand(160,224)));
imageline($image,0,$i,$this->lx,$i,$color);
}
}
// private text to read
for ($i=0,$x=5; $i<$this->long;$i++) {
$r=intval(rand(0,128));
$g=intval(rand(0,128));
$b=intval(rand(0,128));
$color = ImageColorAllocate($image, $r,$g,$b);
$shadow= ImageColorAllocate($image, $r+128, $g+128, $b+128);
$size=intval(rand(14,20)); // lettergrootte
$angle=intval(rand(-10,10)); // hoek van de letter
$text=strtoupper(substr($private_key,$i,1));
ImageTTFText($image,$size,$angle,$x+2,26,$shadow,$this->font_file,$text);
ImageTTFText($image,$size,$angle,$x,24,$color,$this->font_file,$text);
$x+=$size+2;
}
if ($this->imagetype=="jpg")
imagejpeg($image, $this->get_filename(), 100);
else
imagepng($image, $this->get_filename());
ImageDestroy($image);
}
function display_captcha($noise=true) {
$this->make_captcha($noise);
$res="<input type=hidden name='public_key' value='".$this->public_key."'>\n";
$alt="Type deze code van ".$this->long." tekens in het veld hieronder";
$res.="<img src='".$this->get_filename()."' alt='$alt' border='1'>\n";
return $res;
}
}
?>
[/code]
Reacties
0