nachdem eines meiner Seiten Opfer einer massiven Spam-Attacke befallen wurde, entschied ich mich ein Captcha zu erstellen um diesem entgegen zu wirken. Da mir bekannt ist, dass einige Bots/Skripts Captchas lösen können, wollte ich dieses so gut wie möglich unterbinden.
Ich habe daher folgende Sicherheitsvorkehrungen getroffen:
- Das Captcha Bild erstellt die Aufgabe nicht, sondern zeigt sie nur an.
- Das Captcha Bild kann nur von der Seite angezeigt werden, wo es auch angezeigt werden soll.
- Die Captcha Aufgabe kann eine +, -, * oder / Aufgabe sein.
- Sowohl die Captcha Aufgabe als auch das Ergebniss werden in $_SESSION gespeichert und mit Blowfish verschlüsselt.
- Die Abstände zwischen den Zahlen und dem Operator ist immer verschieden.
- (Kommt noch) Die Zahlen und Operatoren werden als Bilder dargestellt um das Auslesen noch schwerer zu machen.
- (Kommt noch) Der Hintergrund wird ebenfalls in Form eines Bildes dargestellt.
Reicht das oder hab ich noch etwas vergessen?
Bevor ich es vergesse ... Wörter die in [< und >] eingeschlossen sind, müssen durch den entsprechenden Wert ersetzt werden.
Also z.B.
muss durch ein Passwort ersetzt werden. (Die [< und die >] dürfen nicht stehen bleiben!)[<PASSWORT>]
Auzug aus der Form-Page
- Code: Alles auswählen
// Direkt am Start eine Session starten
if ( !empty($_GET["id"]) ) {
session_id($_GET["id"]);
}
session_start();
$_SESSION["Refer"] = [<REFERER>];
Hier ist dann das Formular.
Das Captcha Bild braucht aber die Session-ID als Parameter.
Das sieht dann in etwa so aus:
- Code: Alles auswählen
<img src="captcha.php?id=<?php echo session_id(); ?>" alt="">
Das Captcha Bild muss jedoch mit ?id=<?php ech
Eine Aufgabe wird mit
- Code: Alles auswählen
Exer( [<PASSWORT>] );
Diese Funktion befindet sich in einer eigenen Datei.
Diese sieht so aus:
exer.php
- Code: Alles auswählen
/* Captcha Functions - (C) 2010 by anihex */
function Exer($passwort) {
srand();
$Fischi = new Blowfish($passwort);
// Eine zufaellige Aufgabe stellen
$Op = array();
$Op[1] = "+";
$Op[2] = "-";
$Op[3] = "*";
$Op[4] = ":";
$Operator = rand(1, 4);
$Leer1 = rand(1, 3);
$Leer2 = rand(1, 3);
$Min = 1;
$Max = 10;
switch ($Operator) {
case 1:
$Zahl1 = rand($Min, $Max);
$Zahl2 = rand($Min, $Max);
$Ergebnis = $Zahl1 + $Zahl2;
break;
case 2:
$Ergebnis = rand($Min, $Max);
$Zahl2 = rand($Min, $Max);
$Zahl1 = $Ergebnis + $Zahl2;
break;
case 3:
$Zahl1 = rand($Min, $Max);
$Zahl2 = rand($Min, $Max);
$Ergebnis = $Zahl1 * $Zahl2;
break;
case 4:
$Ergebnis = rand($Min, $Max);
$Zahl2 = rand($Min, $Max);
$Zahl1 = $Ergebnis * $Zahl2;
break;
}
$Leer_1 = "";
$Leer_2 = "";
for ($Index = 0; $Index < $Leer1; $Index++) {
$Leer_1 = $Leer_1." ";
}
for ($Index = 0; $Index < $Leer2; $Index++) {
$Leer_2 = $Leer_2." ";
}
$Aufgabe = $Zahl1.$Leer_1.$Op[$Operator].$Leer_2.$Zahl2." = ?";
$Coded = $Fischi->Encrypt($Aufgabe);
$_SESSION["id"] = $Coded;
$Coded = $Fischi->Encrypt($Ergebnis);
$_SESSION["sd"] = $Coded;
}
function GetAnswer($passwort) {
$Fischi = new Blowfish($passwort);
$Res = $Fischi->Decrypt( $_SESSION["sd"] );
return $Res;
}
?>
Das Captcha Bild erwartet nun zum einen die Session-ID und auch eine Variable in der Session, die den Namen "Refer" enthält. Welchen Wert diese Variable haben soll, müsst ihr im Skript nachträglich eintragen.
captcha.php
- Code: Alles auswählen
<?php
/* Captcha Picture - (C) 2010 by anihex */
/* Modified Tutorial of LLCoolDannY */
$Error = 0;
if ( !empty($_GET["id"]) ) {
session_id($_GET["id"]);
} else {
$Error = 0;
}
session_start();
include ("include/blowfish.php");
$Blowfishi = new Blowfish( [<PASSWORT>] );
$Text = $Blowfishi->Decrypt( $_SESSION["id"] );
if ( $_SESSION["Refer"] != [<REFERER>] ) {
$Error = 1;
}
if ( empty($Text) or $Error ) {
$Text = "!! ERROR !!";
}
Header("Content-Type: image/png");
$width = 200;
$height = 40;
$img = ImageCreate($width, $height);
$black = ImageColorAllocate($img, 0, 0, 0);
$white = ImageColorAllocate($img, 255, 255, 255);
ImageFill($img, 0, 0, $black);
ImageString($img, 5, 26, 10, $Text, $white);
ImagePNG($img);
ImageDestroy($img);
unset( $_SESSION["Refer"] );
?>
Ob die Antwort korrekt ist, kann man recht einfach prüfen.
Zum Beispiel so:
- Code: Alles auswählen
$answer = $_POST["answer"];
$ValidCaptcha = 1;
// Prüfen, ob die Antwort korrekt ist
if ( empty($answer) ) {
// Keine Antwort angegeben
$ValidCaptcha = 0;
}
$correct_answer = GetAnswer( [<PASSWORT>] );
if ( (int)$answer != (int)$correct_answer ) {
// Antwort ist falsch
$ValidCaptcha = 0;
}
Beispielseite. Funzt auch
- Code: Alles auswählen
<?php
if ( !empty($_GET["id"]) ) {
session_id($_GET["id"]);
}
session_start();
$_SESSION["Refer"] = "test";
include "include/blowfish.php";
include "include/exer.php";
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Captcha Test</title>
</head>
<body>
<?php
if (strtoupper($_SERVER['REQUEST_METHOD']) == "POST") {
$answer = $_POST["answer"];
$ValidCaptcha = 1;
// Prüfen, ob die Antwort korrekt ist
if ( empty($answer) ) {
// Keine Antwort angegeben
$ValidCaptcha = 0;
}
$correct_answer = GetAnswer("1234567890");
if ( (int)$answer != (int)$correct_answer ) {
// Antwort ist falsch
$ValidCaptcha = 0;
}
if ( $ValidCaptcha ) {
?>
<p>
Captcha is valid!
</p>
<?php
} else {
?>
<p>
Captcha is NOT valid!
</p>
<?php
}
}
Exer("1234567890")
?>
<form action="captchatest.php?id=<?php echo session_id(); ?>" method="POST">
<img src="captcha.php?id=<?php echo session_id(); ?>" alt=""><br>
<input size="20" maxlength="20" name="answer">
<input type="submit" value="Check">
</form>
</body>
</html>
Testseite
Credits:
Captcha Functions : anihex
Captcha Bild : Tutorial von PHP.de, erweitert durch anihex.
BlowFish Implementierung: PHP-Einfach.de
Wie auch immer ... Ist diese Variante sicher oder ist sie unsicherer als die hier vorgschlagene Version?
