skip to content

Captcha-Technik zum Schutz von Webformularen

Dieses Skript schützt Webformulare vor Spam, indem es die Eingabe eines nur für Menschen lesbaren Codes verlangt.

Rechts sehen Sie ein Formular mit einer solchen integrierten Spamprüfung. Das Skript erstellt ein Bild mit einem individuellen Zufallscode und übergibt ihn an das Formular. Nach dem Ausfüllen des Formulars überprüft das Skript dann die Korrektheit des Codes. 

Das Skript funktioniert entweder mit Perl (dann muss das Formular, in dem das Captcha eingebettet werden soll, auch aus einem Perl-Skript generiert werden), oder der Server muss PHP-fähig sein. Um ein Formular mit Perl zu erstellen genügt es, folgende Anweisung in einer Perl-Datei zu speichern und diese ins cgi Verzeichnis des Servers zu legen:

echo 'Hier der HTML-Code des Formulars'

Einbinden in ein Perl-Skript

Um dieses Skript in Ihr Perl-Formular einzubinden gehen Sie bitte wie folgt vor:

Zunächst machen Sie das Captcha-Skript ihrem Skript bekannt:

require "/vol/info/www/bin2/captcha.pl";

Dann lassen Sie das Captcha-Skript einen aktuellen Code mit dem zugehörigen Bild erstellen:

$erstelleformreturn= &erstelleform();

Das Formular liefert den erstellten Code verschlüsselt zurück. Bringen Sie nun folgende Felder in Ihrem Formular unter, um den verschlüsselten Code als Identifier mitzusenden, das Bild anzuzeigen und einem User die Eingabe des Codes zu ermöglichen:

<input type="hidden" name="cap" value="$erstelleformreturn">
<img src="$bilderhp/$erstelleformreturn.png">
<input type="text" name="passwort">

Wenn Sie das Formular auslesen müssen Sie dort auch die beiden eben erstellten Felder auslesen. Beispielsweise so:

my $frage= new CGI;
my $passwort=$frage->param('passwort');
my $cap=$frage->param('cap');

Bevor Sie jetzt das Formular weiterverarbeiten prüfen Sie die Richtigkeit des eingegebenen Codes:

$fehler = &checkform($passwort,$cap);

Der erste übergebene Parameter ist dabei der vom User eingegebene Code und der zweite Parameter der verschlüsselt übergebene Code. Die Funktion liefert folgende Werte zurück, die Sie verwenden können um eine entsprechende Ausgabe zu erstellen beziehungsweise das Formular weiter zu verarbeiten:

0 : Validierung erfolgreich 
1 : Ein falscher captch-Kontroll-Code wurde eingegeben 
2 : Der captch-Kontroll-Code ist abgelaufen (Ein erstellter Code ist aus sicherheitsgründen nur 5 Minuten haltbar)
3 : Der übergebene verschlüsselte captch-Kontroll-Code ist nicht in der Datenbank und daher ungültig

Ein Beispiel-Skript (Perl)

Ein einfaches Perlformular, dass die eingegebenen Daten per Email versendet sieht beispielsweise so aus:

#!/usr/bin/perl

use CGI;

$mailprog = '/usr/lib/sendmail';


my $formular= new CGI;
my $kommentar=$formular->param('kommentar');

if (!$kommentar){

print "Content-Type: text/html\n\n";
print '<html>
<head><title></title></head>
<body>
<form method="post" action="formular.pl">
<input type="text" name="kommentar"><br>
<input type="submit">
</form>
</body>
</html>';
}
else{
open (MAIL, "|$mailprog -t");
print MAIL <<"...";
Subject: Kommentar
To: test@mail.de
From: Mailprogramm

...
print MAIL "Kommentar:\n$kommentar\n";
close MAIL;
}

Wenn man jetzt das Programm mit dem Captcha-Skript ausstattet, sieht es wie folgt aus:

#!/usr/bin/perl

use CGI;

require "/vol/info/www/bin2/captcha.pl";


$mailprog = '/usr/lib/sendmail';



my $formular= new CGI;
my $kommentar=$formular->param('kommentar');
my $passwort=$formular->param('passwort');
my $cap=$formular->param('cap');



if (!$kommentar){

print "Content-Type: text/html\n\n";
print '<html>
<head><title></title></head>
<body>

<form method="post" action="formular.pl">
<input type="hidden" name="cap" value="' .$random_number. '">

<input type="text" name="kommentar"><br>


<img src="'.$bilderhp.'/'.$random_number.'.png"><input type="text" name="passwort"><br>
<input type="submit">
</form>
</body>
</html>';
}
else{

$fehler = &checkform($pass,$cap);
if($fehler==1){

print "Sie haben einen falschen oder keinen captch-Kontroll-Code eingegeben!\n Gehen Sie zurück, aktualisieren Sie das Formular und geben Sie den neuen Code ein.";
}
elsif($fehler==2){
print "Der captch-Kontroll-Code ist leider abgelaufen!\n Gehen Sie zurück und aktualisieren Sie das Formular für einen neuen Code.";
}
elsif($fehler==3){
print "Sie haben einen ungültigen captch-Kontroll-Code eingegeben.\nGehen sie zurück, aktualisieren Sie das Formular und geben Sie den neuen Code ein.";
}
elsif ($fehler==0){


open (MAIL, "|$mailprog -t");
print MAIL <<"...";
Subject: Kommentar
To: test@mail.de
From: Mailprogramm

...
print MAIL "Kommentar:\n$kommentar\n";
close MAIL;
}
}

Einbinden in ein PHP-Skript

Wenn Sie das Skript in ihrem PHP-Formular verwenden wollen gehen Sie bitte so vor:

Lassen Sie einen Code erzeugen und bringen Sie folgende Felder in Ihrem Formular unter, um den verschlüsselten Code als Identifier mitzusenden, das Bild anzuzeigen und einem User die Eingabe des Codes zu ermöglichen:

<input type="hidden" name="cap" value='<?php $erstelleformreturn=system('perl /vol/info/www/bin2/captcha/make_captcha');?>'>
<img src='http://www.uni-koeln.de/rrzk/captcha/<?php echo $erstelleformreturn;?>.png'>
<input type="text" name="passwort">

Wenn Sie das Formular auslesen müssen Sie dort auch die beiden eben erstellten Felder auslesen. Beispielsweise so:

$passwort=$_POST['passwort'];
$cap=$_POST['cap'];

 

Bevor Sie jetzt das Formular weiterverarbeiten prüfen Sie die Richtigkeit des eingegebenen Codes (Hierbei ist zu beachten, dass das der Fehlercode auch an der Stelle ausgegeben wird, an der das Skript aufgerufen wird):

<?php $check_captcha=system("perl /vol/info/www/bin2/captcha/check_captcha $passwort $cap");?>

 

Der erste übergebene Parameter ist dabei der vom User eingegebene Code und der zweite Parameter der verschlüsselt übergebene Code. Die Funktion liefert folgende Werte zurück, die Sie verwenden können um eine entsprechende Ausgabe zu erstellen bzw. das Formular weiter zu verarbeiten:

0 : Validierung erfolgreich 
1 : Ein falscher captcha-Kontroll-Code wurde eingegeben 
2 : Der captcha-Kotroll-Code ist abgelaufen (Ein erstellter Code ist aus sicherheitsgründen nur 5 Minuten haltbar)
3 : Der übergebene verschlüsselte captcha-Kontroll-Code ist nicht in der Datenbank und daher ungültig

Ein Beispiel-Skript (PHP)

Ein einfaches PHP-Formular, dass die eingegebenen Daten per Email versendet sieht bspw. so aus:

<html>
<head>
<title></title>
<meta http-equiv="Content-type" content="charset=iso-8859-1">
</head>
<body>
<?php
if($_POST) {
if(mail('test@test.de', 'Testbetreff', $_POST['kommentar'], "From: Testformular" )) {
echo "<p>Nachricht gesendet!</p>";
} else {
echo "<p>Nachricht konnte nicht gesendet werden!</p>";
}
} else {
?>
<form action="" method="post">
<p>
Kommentar: <textarea name="kommentar" rows="5" cols="40"></textarea><br>
<input type="submit">
</p>
</form>
<?php
}
?>
</body>
</html>

 

Wenn wir dieses Skript nun um die Angaben für die Einbindung des Captcha erweitern erhalten wir folgendes Skript:

<html>
<head>
<title></title>
<meta http-equiv="Content-type" content="charset=iso-8859-1">
</head>
<body>
<?php
if($_POST) {
$passwort=$_POST['passwort'];
$cap=$_POST['cap'];
print "Überprüfungscode= ";
$check_captcha=system("perl /vol/info/www/bin2/captcha/check_captcha $passwort $cap");
print ":\n\n";

if($check_captcha==1){

print "Sie haben einen falschen oder keinen captcha-Kontroll-Code eingegeben!\n Gehen Sie zurück, aktualisieren Sie das Formular und geben Sie den neuen Code ein.";
}
elseif($check_captcha==2){
print "Der captcha-Kontroll-Code ist leider abgelaufen!\n Gehen Sie zurück und aktualisieren Sie das Formular für einen neuen Code.";
}
elseif($check_captcha==3){
print "Sie haben einen ungültigen captcha-Kontroll-Code eingegeben.\nGehen sie zurück, aktualisieren Sie das Formular und geben Sie den neuen Code ein.";
}
elseif ($check_captcha==0){


if(mail('test@test.de', 'Testbetreff', $_POST['kommentar'], "From: Testformular" )) {
echo "<p>Nachricht gesendet!</p>";
} else {
echo "<p>Nachricht konnte nicht gesendet werden!</p>";
}
}
} else {
?>
<form action="" method="post">
<p>
Kommentar: <textarea name="kommentar" rows="5" cols="40"></textarea><br>
<input type="hidden" name="cap" value='<?php $erstelleformreturn=system('perl /vol/info/www/bin2/captcha/make_captcha');?>'>
<img src='http://www.uni-koeln.de/rrzk/captcha/<?php echo $erstelleformreturn;?>.png'>
<input type="text" name="passwort"><br>

<input type="submit">
</p>
</form>
<?php
}
?>
</body>
</html>

Ausgefüllte Felder beim Reload behalten

Wir wollen hier versuchen den Effekt zu umgehen, dass bei einem falsch eingegeben Code das Formular neu geladen werden muss um einen neuen Code zu erzeugen und dabei die Daten der schon ausgefüllten Felder des Formulars verlorengehen. Die Idee ist folgende: Auf der Seite die den Fehler anzeigt, dass ein falscher Code eingegeben wurde wird ein Button bereitgestellt, der das Formular wieder lädt, einen neuen Code generiert und die Daten erhält. Dazu implementieren wir auf der "Fehlerseite" ein Formular, dass alle Felder des Formulars enthält, die auch unser Originalformular enthält allerdings verstecken wir die Felder, da sie für den Anwender nicht interessant sind, sondern nur die schon eingebenen Daten für uns transportieren sollen. Sichtbar bleibt ein Button, den wir mit "zurück" beschriften und der dann die Daten für uns wieder an das Formular sendet, damit wir diese in die entsprechenden Felder eintragen können und der Benutzer auf seine schon eingebenen Daten zurückgreifen kann. Dieser Schritt mit dem nochmaligen senden ist notwendig, da sich das Skript nicht merken kann welcher Benutzer welche Daten eingegeben hat. Wie das jetzt konkret aussieht, zeigen die folgenden Beispiele für Perl und PHP. Wir verwenden wieder die Beispielskripte von weiter oben.

Ausgefüllte Felder beim Reload behalten (Beispiel Perl)

Zunächst das Formular, das in der "Fehlerseite" implementiert werden soll. Wir betrachten daür folgenden Ausschnitt aus dem obigen Beispiel-Skript:

print "Sie haben einen falschen oder keinen captcha-Kontroll-Code eingegeben!\n Gehen Sie zurück, aktualisieren Sie das Formular und geben Sie den neuen Code ein.";

Und verändern ihn wie folgt:

print "
<form action='formular.pl' method='POST'>
<input type='hidden' name='kommentar' value='$kommtentar'>

Sie haben einen falschen oder keinen captcha-Kontroll-Code eingegeben!\n Gehen Sie <input type='submit' name='reload' value='zurück'> aktualisieren Sie das Formular und geben Sie den neuen Code ein.
</form>";

Jetzt nehmen wir uns den Anfang des Skriptes vor. Hier müssen wir jetzt überprüfen, ob das Formular regulär abgesendt wurde, oder ob der Benutzer auf den "zurück" Button gedrückt hat. Wir betrachten folgenden Abschnitt aus dem obigen Beispiel:

my $formular= new CGI;
my $kommentar=$formular->param('kommentar');
my $passwort=$formular->param('passwort');
my $cap=$formular->param('cap');

if (!$kommentar){

Und verändern ihn wie folgt:
my $formular= new CGI;
my $kommentar=$formular->param('kommentar');
my $passwort=$formular->param('passwort');
my $cap=$formular->param('cap');
my $reload=$formular->param('reload');

if (!$kommentar || $reload='zurück'){

Als letztes sorgen wir noch dafür, dass die Daten wieder in das Feld eingetragen werden. Wir betrachten dafür folgenden Ausschnitt:

<input type="text" name="kommentar">

Und ergänzen ihn folgendermaßen:

<input type="text" name="kommentar" value="$kommentar">

Ausgefüllte Felder beim Reload behalten (Beispiel PHP)

Zunächst das Formular, das in der "Fehlerseite" implementiert werden soll. Wir betrachten daür folgenden Ausschnitt aus dem obigen Beispiel-Skript:

print "Sie haben einen falschen oder keinen captcha-Kontroll-Code eingegeben!\n Gehen Sie zurück, aktualisieren Sie das Formular und geben Sie den neuen Code ein.";

Und verändern ihn wie folgt:

print "
<form action='formular.pl' method='POST'>
<input type='hidden' name='kommentar' value='$kommtentar'>

Sie haben einen falschen oder keinen captcha-Kontroll-Code eingegeben!\n Gehen Sie <input type='submit' name='reload' value='zurück'> aktualisieren Sie das Formular und geben Sie den neuen Code ein.
</form>";

Jetzt nehmen wir uns den Anfang des Skriptes vor. Hier müssen wir jetzt überprüfen, ob das Formular regulär abgesendt wurde, oder ob der Benutzer auf den "zurück" Button gedrückt hat. Wir betrachten folgenden Abschnitt aus dem obigen Beispiel:

if($_POST) {

Und verändern ihn wie folgt:

if($_POST && $_POST['reload']!="zurück") {

Als letztes sorgen wir noch dafür, dass die Daten wieder in das Feld eingetragen werden. Wir betrachten dafür folgenden Ausschnitt:

Kommentar: <textarea name="kommentar" rows="5" cols="40">$_POST['kommentar']</textarea>

Und ergänzen ihn folgendermaßen:

<input type="text" name="kommentar" value="$kommentar">

Captchas mit JavaScript und SHTML

Auf dem Hauptwebserver der Uni Köln stellen wir Skripte bereit, die es Ihnen ermöglichen, Captchas auch direkt in Ihre HTML-Seiten einzubinden. Allerdings ist hierfür etwas JavaScript erforderlich.Zunächst ergänzen Sie den Body-Tag Ihrer Webseite wie folgt:

<body onload="javascript:captchaPfad()">

Es folgt die JavaScript-Funktion, die Sie entweder in einen ggf. bereits bestehenden Codeblock einbinden oder als eigenen Codeblock einfügen können:

<SCRIPT language="JavaScript">
<!--
function captchaPfad(){
var randomnr='<!--#include virtual="/cgi-bin/gimmecaptcha.pl" -->';
document.captcha.src=
'http://www.uni-koeln.de/rrzk/captcha/'+randomnr+'.png';document.myform.bildcode.value=randomnr
;
}
//-->
</SCRIPT>

Beachten Sie, dass die Funktion das Formular mit dem Namen "myform" anspricht. Passen Sie also bitte Ihr Formular oder gegebenenfalls die Funktion an.Nun müssen Sie den Zahlencode natürlich noch im Kontext Ihres Formulars darstellen und eine Eingabemöglichkeit schaffen, zum Beispiel wie folgt:

Zahlencode:
<br>(siehe Bild)<br><img name="captcha" src="">
<input type="text" name="cap" maxlength="4" size="5">

Zusätzlich benötigen Sie noch die folgende Zeile (ebenfalls im Kontext des Formulars):

<input type="hidden" value="" name="bildcode">

Das Formular können Sie nun mit Ihrer Lieblingsprogrammiersprache auswerten, die benötigten Parameter zur Captcha-Verifizierung lauten "bildcode" und "cap". Falls Sie Perl verwenden, sieht das Ganze zum Beispiel so aus:

require "/vol/info/www/bin2/captcha.pl";
my $formular= new CGI;
my $passwort=$formular->param('passwort');
my $cap=$formular->param('cap');
$fehler = &checkform($pass,$cap);
if($fehler==1){
print "Falscher oder kein captcha-Kontroll-Code eingegeben!";
}
elsif($fehler==2){ print "captcha-Kontroll-Code abgelaufen!"; }
elsif($fehler==3){ print "Ungültiger captcha-Kontroll-Code!"; }
elsif ($fehler==0){
// Hier folgen Ihre Anweisungen, der Captcha-Code war korrekt

Für Python ist ein kleiner Umweg erforderlich, den wir aber durch ein weiteres bereitgestelltes Skript vereinfachen. Beispiel:

import os, cgi
form = cgi.FieldStorage()
fehler = os.system("perl /vol/info/www/cgi-bin/checkcaptcha.pl " + form.getvalue('bildcode') + " " + form.getvalue('cap'))
if fehler==256:
print("Falscher oder kein captcha-Kontroll-Code eingegeben!")
elif fehler==512:
print("captcha-Kontroll-Code abgelaufen!")
elif fehler==768:
print("Ungültiger captcha-Kontroll-Code!")
elif fehler==0:
# Hier folgen Ihre Anweisungen, der Captcha-Code war korrekt

(Anmerkung: Falls Sie sich über die hohen Zahlen der Fehlercodes wundern, das liegt an der 8-Bit-Verschiebung zwischen Perl- und Shell-Rückgabewerten.)

Contact
If you have any questions or problems, please contact the RRZK-Helpdesk