Spamfreie Formulare
Spamfrei ohne Captcha o. ä.
Achtung: Überarbeitete Version 1.5 für UTF8 veröffentlicht (20.02.2022).
Die neue Version funktioniert mit PHP 7 und PHP 8 und UTF8.
Download Kontaktformular 1.5 für UTF8
Achtung: Überarbeitete Version 1.4 für UTF8 veröffentlicht (13.05.2012).
Die ursprüngliche Version 1.4 funktioniert nicht mit UTF8-Websites. Wer UTF8 einsetzt, sollte die angepasste Version
verwenden. Mehr dazu hier im Forum.
Download Kontaktformular 1.4 für UTF8
Achtung: Überarbeitete Version 1.4 veröffentlicht (28.10.2009).
Es wird weiterhin das Tutorial zum Verständnis empfohlen.
Diese Version ermöglicht Radio- und Dropdown- (Select-) Felder und behebt Bugs aus 1.3.
Außerdem kann der Mailbetreff nun fest sein.
Download Kontaktformular 1.4
Achtung: Überarbeitete Version 1.3 veröffentlicht (19.03.2009).
Weitreichend überarbeitet, damit beliebig viele Felder leicht eingefügt werden
können. Die neue Version ist funktional ausgerichtet und nicht so leicht
verständlich wie Version 1.2. Deshalb wird das Tutorial beibehalten und zum
Verständnis empfohlen.
Version 1.3 soll lediglich eine einfache Anpassung der Felder ermöglichen.
Diese Version enthält Bugs und ist daher nicht mehr zum Download verfügbar. Verwenden Sie Version 1.4
Achtung: Überarbeitete Version 1.2 veröffentlicht (27.01.2009).
Geändert wurde:
1. Bei Fehlern stehen die eingegebenen Werte noch im Formular
2. alle Werte (vor allem der Name) erscheinen nochmal im Nachrichtentext.
In den Tutorial-Text wurde nur 2. übernommen, zu 1. siehe Download Kontaktformular 1.2.
Dieses Tutorial beschreibt, wie man ohne Captchas, zusätzliche Eingabe-Felder ("Was ist 2+4?") oder ähnlichem spamfreie Formulare erstellt. Die Formulare werden ausschließlich technisch verändert, der Nutzer bemerkt keinen Unterschied zu einem normalen Formular. Dies ist nicht möglich? Das dachte ich auch - wie naiv ;)
Das Verfahren lässt sich nicht nur - wie im Beispiel gezeigt - in PHP sondern in jeglicher serverseitigen Programmiersprache umsetzen.
Voraussetzungen zum Verständnis: Kenntnisse in HTML (Formulare) und PHP oder einer anderen serverseitigen Programmiersprache
Keine Lust zum Lesen und einfach nur ein spamfreies Kontaktformular downloaden?
Es funktioniert
Versprochen. Auf einer Seite mit an die 100 Spam-Posts am Tag wurden die Formulare wie in diesem Tutorial beschrieben verändert. Seitdem (schon über ein halbes Jahr her) kam nicht ein Spam-Post durch (bis auf die von Menschen manuell abgeschickten). Das sind schätzungsweise über 18.000 geblockte Spam-Posts. Dabei werden keine "normalen" Posts geblockt, wie es bei filterbasierten Lösungen vorkommt.
Die Idee
Die Idee ist einfach: Man überlegt, welche Aufgabe beim Ausfüllen eines Formulars nur ein Mensch kann. Dabei muss man keine künstlichen Barrieren wie etwa ein Captcha einführen. Eine klassische Aufgabe, die einer Maschine Probleme bereitet ist die Frage, in welches Feld die Mailadresse kommt (falls das Formular eine Mailadresse verlangt). Dieses Problem kann eine Maschine nur lösen, wenn ein Bezug durch Feldnamen wie name='mail' o.ä. leicht herzustellen ist. Die Feldbeschriftung kann eine Maschine dem Feld schlecht zuordnen. Um hier die Schwierigkeit noch zu erhöhen, kann man zusätzlich die Feldbeschriftung in ASCII "verschlüsseln".
Man wählt also nichts sagende Feldnamen und verlangt durch das PHP-Script, dass im Mail-Feld eine gültige Mailadresse steht und in keinem anderem Feld (Wer heißt schon so wie seine Mailadresse?). Dadurch verhindert man, dass der Bot in alle Felder Mailadressen einfüllt.
Da der Spam-Bot theoretisch durch Ausprobieren das richtige Feld für die Mailadresse finden kann (sofern er sehr intelligent ist), und um das ganze noch etwas sicherer zu machen, werden die Feldnamen nicht einfach nur nichtssagend gewählt: Sie ändern sich auch noch. Und das einmal am Tag. Jeden Tag haben alle Felder komplett andere, und stets nichtssagende Namen.
Der ein oder andere wird sich jetzt um Barrierefreiheit Gedanken machen. Ja, solche Formulare sind nicht barrierefrei. Aber Captchas sind es auch nicht. Und wer Barrierefreiheit erreichen will, kann das leicht tun: Indem er ein alternatives Formular mit Audio-Captcha zur Verfügung stellt, welches durch labels und "normale" Feldnamen die Zuordnung ermöglicht.
Nichtssagende Namen
Mein Algorithmus um diese Namen zu erzeugen ist simpel:
Feldbezeichnung + AntiSpam-Satz + Tag des Monats
Die Feldbezeichnung stellt die Zuordnung sicher. Der Tag des Monats sorgt für die tägliche Änderung der Feldbezeichnung. Damit die Bezeichner nichtssagend werden, wird der MD5-hash vom ganzen String gebildet. Der Antispam-Satz ist eine zusätzliche Hürde, da sich kurze MD5-Hashs in Datenbanken nachschlagen lassen. Ein langer angehängter Satz macht dies
quasi unmöglich. Dadurch lässt sich aus dem MD5-Hash (auch von einem
Menschen) die Feldbedeutung nicht ermitteln. Menschen können ja aber einfach
die Feldbeschriftung lesen ;)
Dadurch, dass jede Seite einen anderen Antispam-Satz verwendet, lässt sich der Feldname selbst wenn man den Algorithmus kennt nicht erraten.
Beispiel-Implementierung: PHP-Kontaktformular
Hier soll die Umsetzung des Verfahrens am Beispiel eines PHP-Kontaktformulars gezeigt werden.
Zunächst müssen die Bezeichner für die Felder generiert werden:
<?php
/* kontakt.php */
/* TEIL 1 */
// Antispam-Satz
$unique_str='Der Anti-Spam-Satz: Irgendein langer satz damit das sehr spam-sicher wird...';
// Datum anhängen
$antispam_str=$unique_str.date('d');
// Feldbezeichner generieren
$name_key=md5('name'.$antispam_str);
$mail_key=md5('mail'.$antispam_str);
$betreff_key=md5('betreff'.$antispam_str);
$nachricht_key=md5('nachricht'.$antispam_str);
?>
Allerdings muss hier noch ein Sonderfall beachtet werden: Angenommen ein Besucher ruft die Formularseite um 23:59 auf. Das Formular hat noch die alten Bezeichner. Schickt er das Formular um 00:00 ab, sind die alten Bezeichner nicht mehr gültig.
Die Lösung: Zwischen 00 und 1 Uhr nachts werden die Bezeichner des Vortages auch noch akzeptiert. Wer länger als eine Stunde zum Ausfüllen des Formulars benötigt, ist selber Schuld (natürlich lässt sich der Zeitraum auch auf 2 oder 3 Stunden erhöhen).
Die Umsetzung:
<?php
/* kontakt.php */
/* TEIL 1 */
// …
/* TEIL 2 */
if(date('H')=='00')
{
// Es ist 0 Uhr. Eventuell hat jemand vor 0 Uhr das Form abgesendet.
// Deshalb wird auch der Key von Gestern akzeptiert.
$antispam_str2=$unique_str.date('d',time()-86400);
$name_key2=md5('name'.$antispam_str2);
$mail_key2=md5('mail'.$antispam_str2);
$betreff_key2=md5('betreff'.$antispam_str2);
$nachricht_key2=md5('nachricht'.$antispam_str2);
}
else
{
$name_key2=$name_key;
$mail_key2=$mail_key;
$betreff_key2=$betreff_key;
$nachricht_key2=$nachricht_key;
}
?>
Jetzt erzeugen wir das Formular:
<?php
/* kontakt.php */
/* TEIL 1 */
// …
/* TEIL 2 */
// …
?>
<!--HTML-FORM - -->
<form action="kontakt.php" method="post">
<table style="width:100%">
<tr>
<td width="20%">
Name:
</td>
<td width="80%">
<input type="text" name="<?php echo $name_key; ?>" style="width:100%" />
</td>
</tr>
<tr>
<td width="20%">
E-Mail:
</td>
<td width="80%">
<input type="text" name="<?php echo $mail_key; ?>" style="width:100%" />
</td>
</tr>
<tr>
<td width="20%">
Betreff:
</td>
<td width="80%">
<input type="text" name="<?php echo $betreff_key; ?>" style="width:100%" />
</td>
</tr>
<tr>
<td width="20%" valign="top">
Nachricht:
</td>
<td width="80%">
<textarea name="<?php echo $nachricht_key; ?>" rows="15" style="width:100%"></textarea>
</td>
</tr>
</table>
<input type="submit" value="Abschicken" />
</form>
Hier wurden die Feldbeschriftungen im HTML zur Sicherheit in ASCII "verschlüsselt". Dies erschwert es Bots, den Feldern eine Bedeutung zuzuordnen. Als Feldnamen werden die erzeugten verwendet.
Eine weitere denkbare Hürde wäre es, die Feldbezeichner per CSS zu platzieren und im Quelltext ganz woanders unterzubringen. Für einen Bot wäre eine Zuordnung dann quasi unmöglich. Aber Vorsicht: Nicht als id oder class etwas Aussagekräftiges wie "mail" verwenden!
Jetzt muss das Formular nurnoch ausgewertet werden:
<?php
/* kontakt.php */
$empfaenger='mail@dres.se';
/* TEIL 1 */
// …
/* TEIL 2 */
// …
function check_email ($email)
{
if(eregi("^[a-z0-9]+([-_\.]?[a-z0-9])+@[a-z0-9]+([-_\.]?[a-z0-9])+\.[a-z]{2,4}", $email))
return true;
else return false;
}
if((isset($_POST[$name_key]) && isset($_POST[$mail_key]) && isset($_POST[$nachricht_key])
&& isset($_POST[$betreff_key])) || (isset($_POST[$name_key2]) && isset($_POST[$mail_key2])
&& isset($_POST[$nachricht_key2]) && isset($_POST[$betreff_key2])))
{
$name=(isset($_POST[$name_key])?$_POST[$name_key]:$_POST[$name_key2]);
$mail=(isset($_POST[$mail_key])?$_POST[$mail_key]:$_POST[$mail_key2]);
$nachricht=(isset($_POST[$nachricht_key])?$_POST[$nachricht_key]:$_POST[$nachricht_key2]);
$betreff=(isset($_POST[$betreff_key])?$_POST[$betreff_key]:$_POST[$betreff_key2]);
if(empty($name) || empty($mail) || empty($betreff) || empty($nachricht))
echo "<p><a href='javascript:history.back()'>Fehler:
Ihre Angaben sind unvollständig!</a></p>";
else
{
if(!check_email($mail))
{
echo "<p><a href='javascript:history.back()'>Fehler: Die angegebene E-Mail-Adresse ist
ungültig!</a></p>";
}
else
{
// Setze Nachricht zusammen (eingefuegt am 27.01.2009)
$nachricht = "Betreff: $betreff\nName: $name\nE-Mail: $mail\nNachricht:\n$nachricht";
@mail($empfaenger,$betreff,$nachricht,'From: '.$mail)
or die ("<p><a href='javascript:history.back()'>Fehler:
Daten konnten nicht gesendet werden.</a></p>");
echo "<p>Ihre Angaben wurden erfolgreich versendet.<br />Vielen Dank.</p>";
}
}
}
?>
<!--HTML-FORM - -->
<!-- … -->
Fertig. Die komplette Datei können Sie hier herunterladen:
http://www.christosoft.de/_download/kontakt_1-2.zip
Oder Version 1.4 hier:
http://www.christosoft.de/_download/kontakt_1-4.zip
Eine Erweiterung um weitere Felder ist recht simpel. Es muss auch nicht die Mailadresse sein, die überprüft wird. Jedes andere Pflichtfeld, welches sich auf Gültigkeit überprüfen lässt und das keine zu freie Form hat, ist bestens geeignet. Aber auch eine Kombination aus mehreren
Feldern ist möglich.
Beachten Sie, dass die Funktion check_mail durch eine schnellere preg_match-Funktion ersetzt werden sollte.
Ohne helfende Feldnamen wird es eine Maschine nie schaffen, ein komplexes Formular korrekt auszufüllen, wenn alle Felder auf Plausibilität überprüft werden. Zur Plausibilitätsprüfung sind reguläre Ausdrücke bekanntlich ein wahres Wundermittel. Umso mehr Felder das Formular hat, umso leichter ist es, durch Plausibilitätsprüfungen Bots auszuschließen.
Beachten Sie bitte: Es handelt sich bei der gezeigten Implementierung um eine möglichst leicht verständliche Umsetzung.
Die Zuordnung Feldname/Feld ist hier durch einen auf das Verfahren angepassten Bot natürlich immernoch möglich.
Allerdings gehen Bots den Weg des geringsten Widerstands: Solange noch genug völlig ungeschützte Formulare im Web stehen, macht sich keiner
die Mühe, wegen einer Hand voll Webseiten mit leichten Schutzbarrieren einen intelligenten und damit weniger performanten Bot zu schreiben.
Und sollte das doch passieren, bietet das Verfahren noch reichlich Möglichkeiten, es dem Bot schwer bis unmöglich zu machen:
Positioniert man die Feldbezeichner per CSS neben den Feldern und packt sie in zufälliger Reihenfolge in den Quellcode,
so müsste der Bot schon einen halben Browser mitbringen, der CSS interpretieren kann, um die Zuordnung hinzubekommen.
Und sollte er auch das können, packen wir die Feldbezeichner einfach in ein Bild.
Dann müsste er (wie die Captcha-Bots) noch die Bilder interpretieren können.
Bis es soweit ist, haben wir mit dem Verfahren auf jeden Fall erstmal ein paar Jahre Ruhe.
Haben Sie Anregungen oder Verbesserungsvorschläge? Setzen Sie das Verfahren erfolgreich ein?
Schreiben Sie mir! Natürlich über mein spamsicheres Kontaktformular.