PHP Formular Spamschutz und Validierung – Spam Emails verhindern auch ohne Captcha


Spam Emails aus Formularen verhindern

Spammer benutzen Spambots  die das Internet nach Formularen durchsuchen und diese automatisch auszufüllen und abzusenden. Gängige Abwehrmethode ist das bekannte Captcha, das allerdings auch häufig den Benutzer abwehrt, weil dessen kryptische Zeichen und Zahlen nicht gut zu entschlüsseln sind. Deshalb möchte ich hier Methoden vorstellen die ohne Captcha auskommen. Die gute Nachricht ist, Spambots haben Schwächen, die wir uns im Folgenden zu nutze machen werden. Dazu wird es offensichtliche und versteckte Methoden geben, die in Kombination einen sehr guten Spamschutz bieten sollten.

HTML Markup Demo

1. Abwehr – Checkbox Schwäche

Die offensichtliche Methode ist die Checkbox am Ende des Formulars, hier bestätigt der Benutzer, dass er es ernst meint. Ältere Spambots  können sehr gut Eingabefelder ausfüllen aber keine Checkboxen aktivieren. Somit hätten wir hier schon die erste Abwehr. Bei der Validierung können wir nun prüfen ob die Checkbox markiert wurde, ist das nicht der Fall, bekommt der reale Benutzer eine Meldung und kann es nachholen, der Spambot allerdings dreht sich im Kreis, weil er die Meldung nicht versteht, das Formular aber ohne Aktivierung nicht abgeschickt werden kann.

Da es sich bei einer Checkbox auch nur um ein HTML Element handelt, können modernere Spambots natürlich auch Checkboxen manipulieren und aktivieren. Das machen wir uns in der nächsten Methode zu nutze, indem wir eine Checkbox platzieren die nicht aktiviert werden darf. Bei der Validierung können wir nun prüfen ob diese Checkbox tatsächlich nicht aktiviert wurde oder ob der fleißige Spambot in seinem Eifer doch den Haken gesetzt hat. Wenn er es hat, wird das Formular nicht abgeschickt werden können.

2. Abwehr – CSS Schwäche

Damit die zweite Checkbox den realen Benutzer nicht verwirrt greifen wir auf eine weitere Schwäche der Spambots zurück. Sie können mit CSS Regeln nichts anfangen, deshalb platzieren wir die zweite Checkbox in einem Container, den wir via CSS Klasse ausblenden.

Wichtig hierbei ist den Container über die Klasse auszublenden. Das Ausblenden durch Inline CSS   <div style="display:none">...</div>  oder  <input type="checkbox" style="display:none"> ist nicht geeignet, da Spammer nicht schlafen solche Angaben bereits auswerten können und das Eingabefeld dann ignorieren. Bei Ausblenden via Klasse müsste der Spambot erst einen Abgleich mit der externen CSS Datei machen, was die Hürde weiter nach oben setzt. Für reale Benutzer die CSS deaktiviert haben oder einen Screen Reader benutzen können wir im ausgeblendeten Container eine Mitteilung hinterlassen die auffordert die Felder frei zu lassen.

3. Abwehr – Honeypot

Als Honeypot bezeichnet man Eingabefelder, die vom realen Benutzer frei gelassen werden, den Spambot aber zum Ausfüllen einladen. Bei der PHP Validierung des Formulars prüfen wir dann, ob das Feld tatsächlich leer ist. Ist es nicht leer, konnte der Spambot dieser Versuchung nicht widerstehen und wir haben  die Möglichkeit ihn auszuschließen. Fügen wir unserem Formular also ein weiteres Eingabefeld hinzu

Der Name des Eingabefeldes sollte so attraktiv wie möglich sein, denn Spambots lernen ständig dazu und ignorieren gekonnt Eingabefelder die darauf schließen lassen, dass sie der Spamabwehr dienen. Im Beispiel heißt das Feld name="repeat_email" . Deshalb heißen die Checkboxen oben name="gender" und   name="terms" ,vor allem  Terms sind vor dem Absenden immer zu bestätigen, was den Spambot zum aktivieren animiert. Reingefallen! Zurück zum Honeypot, da das Eingabefeld leer bleiben soll, brauchen wir es dem realen Benutzer nicht zeigen. Positionieren wir dieses Eingabefeld also im ausgeblendeten CSS Container und machen uns dabei gleich eine weitere Schwäche von Spambots zu nutze.

4. Abwehr – Javascript Schwäche

Die meisten Spambots crawlen das Web mit deaktivierten Javascript. Also fügen wir das neue Eingabefeld per Javascript ein.

Da auf meinen Websites jQuery  im Einsatz ist,  füge ich das Eingabefeld via jQuery .append() hinzu und positioniere es im ausgeblendeten Container, so dass der reale Benutzer es nicht sieht. Kommt nun ein Spambot mit deaktivierten Javascript vorbei, wird der jQuery Code nicht ausgeführt und das Feld ist für den Spambot nicht sichtbar.

Für Benutzer mit deaktivieren Javascript können wir mit <noscript> eine entsprechende Meldung hinterlassen. An der Stelle frage ich mich, wie wohl das Surferlebnis ohne Javascript heutzutage ausschaut, bei all den modernen Javascript Elementen auf den Websites.

PHP Validierung

Nach der Kür nun die Pflicht. Validieren wir die Eingaben mit PHP.

Zur Überprüfung der Eingaben nutzen wir einfachstes PHP, was nochmal eine Verbesserung der Spamabwehr darstellt, denn wie oben erwähnt sind viele Spambots mit deaktivierten Javascript unterwegs, was Validierung via Javascript völlig wirkungslos macht.

Gehen wir kurz durch den Code. Wenn das Formular abgeschickt ist, setzen wir  $spamcheck = false; , prüfen wir nun die versteckten Spamelemente damit diese den Spambot in frühster Phase ausbremsen. Mit   if(!isset($_POST["repeat_email"]) || !empty($_POST["repeat_email"]) || isset($_POST["terms"])) { ... } prüfen wir ob unser via Javascript eingefügtes Feld vorhanden ist, weiter wird geprüft ob die beiden versteckten Felder leer gelassen wurden. Ist eines davon nicht leer, speichern wir eine Fehlervariable. Sind beide Felder leer setzen wir   $spamcheck = true; Wurde der Spamcheck bestanden validieren wir nun die anderen Formulareingaben, unter anderen auch die offensichtlich Checkbox die uns auch zur Spamabwehr dient.  if(!isset($_POST["gender"])){ ... } Auftretende Fehler speichern wir wieder im Fehlerarray. Wurden der Spamtest bestanden  if(isset($_POST['submit']) && empty($errors) && $spamcheck == true) { ... } und es sind keine Validierungsfehler vorhanden, können wir das Formular verarbeiten. Je nach Anwendung entweder mit einem Eintrag in die Datenbank oder halt mit versenden einer Email.

Sorgen wir noch dafür, dass  Benutzer die Fehlermeldungen zu sehen bekommt und positionieren folgenden Code über dem Formular. Hier wandeln wir die Einträge der Fehlervariable in eine Liste um und geben diese aus.

 Fazit

Spamabwehr wird auch in Zukunft ein heißes Thema sein. Spam wirksam abwehren bedeutet immer auch Abstriche. Vor allem Abstriche in Hinblick auf Nutzerfreundlichkeit und/oder Barrierefreiheit. Ich habe oben genannte Variante bei einigen Formularen jetzt schon eine Weile erfolgreich im Einsatz. Ich bin gespannt wie lange es dauert, bis ich auch über eines dieser Formulare mit Spam bombardiert werde.

Ich habe ein erweitertes Kontaktformular erstellt, was oben genannte Elemente beinhaltet und zusätzlich auch die restlichen Eingabefelder per PHP validiert. Es ist soweit unformatiert, damit ihr es für eure Bedürfnisse anpassen könnt.

Demo Formular Download Code

Hinweis in eigener Sache!

Das Script ist meine persönliche Lösung, ich erhebe keinen Anspruch darauf, dass diese auch die Beste ist. Änderungen, Verbesserungen und Optimierungen am Script sind ausdrücklich erlaubt. Die Benutzung des Scriptes erfolgt auf eigene Gefahr. Für eventuelle Schäden, die durch den Einsatz bzw. die Nutzung des Scriptes entstehen, übernehme ich keine Haftung.

29.10.2013 Autor: Rico Loschke Kategorie: Demos & Tutorials 6



21 Antworten zu “PHP Formular Spamschutz und Validierung – Spam Emails verhindern auch ohne Captcha”

  1. Mattias Geigenberger sagt:

    Hallo Rico,
    deine Lösung der Spamvermeidung hört sich sehr gut und nutzerfreundlich an! Ich werde sie demnächst ausprobieren. Vielen Dank dafür, auch für die anderen Tutorials.

    Gruß aus Mannheim
    Mattias

    P.S.
    Bin durch Zufall auf deinen Blog gestoßen und werde ihn ab jetzt öfter besuchen 🙂

  2. Lead sagt:

    Gute Zusamenfassung!
    Eins wundert mich nur, wenn ich repeat_email per JS hinzufüge, ist doch bei einem nicht-JS-fähigem Bot das Feld eh nicht vorhanden, also bringt die Prüfung ob leer dann doch nichts?

    • sevenx sagt:

      Man sieht du hast dich mit der Thematik auseinander gesetzt. 🙂 Da ist mir beim Schreiben wohl eine entscheidende Prüfung verloren gegangen. Das via jQuery eingefügte Feld macht natürlich nur Sinn, wenn wir auch dessen Vorhandensein prüfen. Für Spambots mit deaktivierten Javascript ist das Feld nicht vorhanden, was mir die Möglichkeit gibt den Spambot direkt an dieser Stelle abzufangen.

      Der Spamcheck muss entsprechend um: !isset($_POST['repeat_email'] ergänzt werden. So ist es auch in meiner lokalen Vorlage zum Tutorial, irgendwie aber nicht in der Liveversion. Ich habs jetzt ergänzt und danke dir für deine Aufmerksamkeit.

  3. Tobias sagt:

    Hallo, dass Tut. ist wirklich gut und Informationsreich, aber wenn ich die Demo probiere kann ich auch nicht versenden, ich bekomme immer die Meldung Zusatzfeld wurde gefüllt … Das liegt wohl daran das der Browser es automatisch füllt?! da würde ich noch diese Anweisung hinzufügen „autocomplete=“off“ “ zumind. für andere 🙂 Aber sonst sehr Hilfreich.. Lg Tobias

    • sevenx sagt:

      Vielen Dank für den Hinweis. Autocomplete ist bei mir abgeschalten, daher ist das noch nicht aufgefallen. Habs ergänzt. Danke

  4. Christian sagt:

    Hey,

    möchte dein Formular gerne testen, allerdings fehlt mir die dazugehörige „basic-forms.php“.
    Wo kann ich diese denn finden? Müsste ja auch noch meine Empfängeradresse im Formular einrichten.

    Ich Danke dir!

    • sevenx sagt:

      Den Code kannst du dir unter: https://gist.github.com/loschke/7222414 kopieren. Er ist unformatiert aber funktionstüchtig. Grüße

      • Christian sagt:

        Vielen Dank,
        läuft jetzt bei mir. Bin in PHP noch nicht sehr bewandert und wusste nicht, dass man den eigentlichen Versand per Mail noch manuell einprogrammieren muss…

        Grüße!

      • jimmy sagt:

        Hi,
        so richtig kapier ich das jetzt nicht…. das ist doch kein fertiges Skript oder? Irgendwo muss ich doch meine E-Mail-Adresse angeben an die das Formular geschickt werden soll… kann man mir da weiterhelfen? Finde nämlich die Lösung an sich sehr schön 🙂

  5. Jean sagt:

    Perfekte Anleitung inkl. der Ergänzungen!!! Toll!

  6. Jochen sagt:

    Hallo, vielen Dank für die Tolle Beschreibung. Hab noch eine kleine Frage, wäre es möglich nach dem abschicken eine OK Meldung ausgeben zu lassen, unterhalb dem Formular, sprich ich speichere eine Variable und lass diese dann ausgeben?

    • Jochen sagt:

      Hab es nun so umgesetzt:

      $info_sys = ‚Wir haben Ihre Nachricht erhalten und werden uns umgehend bei Ihnen melden‘;

      Und etwas weiter unten lass ich dann diese Meldung ausgeben:

  7. dennis sagt:

    Vielen Dank lieber Rico, hat geholfen und wird meinem Template hingefügt als best practicelösung 🙂

    Gruß
    dennis

  8. Uwe sagt:

    Hallo, ich möchte dich mal auf einen logischen Fehler aufmerksam machen. Du hast unter „//Eingaben validieren“ folgende if-Anweisung:

    if($spamcheck = true) {
    ….weitere Anweisungen
    }

    Da hier nur ein Gleichheitszeichen gesetzt ist, ist die Überprüfung immer wahr. Denn ein Gleichheitszeichen ist eine Zuweisung, kein Vergleich.

    Es müsste also heissen:

    if($spamcheck == true) {
    ….weitere Anweisungen
    }

    oder so

    if($spamcheck) {
    ….weitere Anweisungen
    }

    Denn standardmässig überprüft die if-Bedingung immer auf true.

    Ich hoffe, ich konnte helfen 😉

    VG Uwe

    • sevenx sagt:

      Hallo Uwe, das ist natürlich vollkommen richtig. In der zweiten Prüfung weiter unten steht es richtig drin. Vielen Dank für deine Aufmerksamkeit und deinen Hinweis. Ist jetzt geändert.

  9. KmX sagt:

    Sehr Sehr Sehr Geil

    Ich Danke dir für diese Anleitung.
    Hab minimale PHP Kenntnisse aber mit deinem Skrip is alles klar und ich konnt mir mein Formmailer zusammen basteln.

    Echt nochtmals
    Besten Dank dafür

  10. jimmy sagt:

    Hi,
    so richtig kapier ich das jetzt nicht…. das ist doch kein fertiges Skript oder? Irgendwo muss ich doch meine E-Mail-Adresse angeben an die das Formular geschickt werden soll… kann man mir da weiterhelfen? Finde nämlich die Lösung an sich sehr schön 🙂

  11. Miss M sagt:

    Hallo Rico,
    das ist ein wirklich gelungenes Tutorial. Vielen vielen Dank!! In der Demoversion hast du diese Checkbox „Ich bin kein Spam“ eingebaut, dazu habe ich folgende Frage: Wenn ich an dieser Stelle eine Logikfrage mit Auswertung einbringen wollen würde z.B. Wie hieß mein erstes Haustier? (richtige Antwort: Hansi) Wie würde sowas aussehen?

    Viele liebe Grüße
    Mandy

  12. Mandy sagt:

    Hi Rico,
    ich bin begeistert, genau das wonach ich gesucht habe.
    Sagmal, geht anstelle der „ich bin kein Spamer Checkbox“ auch eine Logikfrage mit Auswertung, wie z.B. „Wie hieß mein erstes Haustier?“ (richtige Antwort: Hansi)
    Wie würde sowas aussehen?
    Bzw. was müsste ich ändern?

    Viele liebe Grüße
    Mandy

  13. Joe Troppmair sagt:

    Hallo Rico!
    Mit diesem Skript zeigst Du eine ideale Alternative zu alles Captchas auf! – Einfach super.

    Trotzdem habe ich hier eine Frage, da ich das Skript derzeit testen möchte:
    Nach
    if(isset($_POST[’send‘]) && empty($errors) && $spamcheck == true) {

    //Formular weiter verarbeiten
    …}
    }
    möchte ich den phpmailer aufrufen, um eine Email zu erzeugen – letztlich bekomme ich aber weder einen Error, noch eine Mail, sondern es bleibt das Formular mit den Eingaben am Schirm stehen…

    Direkt hinter dem //Formular weiterverarbeiten setze ich meinen Code dazu:

    $receiver = „trojo@gmx.at“;
    $subject = $_POST[’subject‘];
    $name = $_POST[’name‘];
    $str = $_POST[’street‘];
    $plz = $_POST[‚plz‘];
    $ort = $_POST[‚city‘];
    $telefon = $_POST[‚phone‘];
    $email = $_POST[‚email‘];
    $bemerkung = $_POST[‚message‘];

    require(„class.phpmailer.php“);
    $mail = new PHPMailer();
    $mail->CharSet = ‚utf-8‘;
    #$mail->IsSMTP();
    $mail->IsSendmail();
    $mail->Host = „mrvnet.kundenserver.de“;
    $mail->SMTPAuth = false;
    $mail->From = „$email“;
    $mail->FromName = „$name“;
    $mail->AddAddress(„$receiver“,““);
    $mail->Subject = „$subject“;
    $mail->IsHTML(true);
    $mail->Body = „–HTML-Code mit den Variablen–„;
    $mail->AltBody = „Ihre Email wurde erfolgreich zugestellt!Ihr Email-Client verweigert aber die Anzeige von HTML-Code – daher erhalten Sie nur diese Nachricht!“;

    if(!$mail->Send()) {
    echo ‚Message was not sent.‘;
    echo ‚Mailer error: ‚ . $mail->ErrorInfo;
    } else {
    echo ‚Message has been sent.‘;
    }

    Übersehe ich da etwas?
    Danke für kurze Auskunft, Joe

  14. Salvatore sagt:

    Hallo,

    Danke für diese gute Anleitung.
    Wie schaffe ich es die Error Nachrichten direkt unter das Eingabefeld zu plazieren, zu denen Sie auch gehören??

    Somit hätte ich nicht am Anfang so einen riesen roten Block.

    Danke im voraus

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.