Formmailer sind unbestreitbar praktisch, um schnell und bequem eine E-Mail verschicken zu können. Eigentlich sollte fast jede gute Seite eine Kontaktaufnahme über einen Formmailer anbieten. Ich habe meine Hauptseite überarbeitet und dabei auch meinen Formmailer neu geschrieben. Seltsamerweise hatte ich früher nie Probleme mit Spam und Formmailer-Missbrauch, aber seit ich meine Website geupdatet habe, werde ich plötzlich auch Opfer von Spam. Aus diesem Grunde habe ich einen einfachen Spamfilter für PHP geschrieben, aber bevor ich darauf eingehe, ist es sinnvoll, sich erstmal anzugucken, wie E-Mails aufgebaut sind und wie sich Formmailer missbrauchen lassen.
Eine E-Mail besteht zunächst aus einem Kopf, dem Header, dessen Inhalt von den E-Mail-Programmen größtenteils nicht angezeigt wird. Dieser Header enthält Informationen über den Absender, über den Weg, den die E-Mail gegangen ist, wann sie abgeschickt wurde, wer eine Kopie erhalten hat und noch einiges mehr. Der Aufbau des Headers ist durch RFC 2822 spezifiziert. Nach dieser Spezifikation werden die Informationen in Header Fields abgelegt und die Header Fields müssen am Anfang einer Zeile stehen, also am Ende einen Zeilenumbruch beinhalten. Typische Header-Informationen sind From, To, Received und Date. Ein E-Mail-Header sieht durch die Spezifikation ungefähr so wie dieses Beispiel aus:
Um einen Formmailer zu missbrauchen, muss man eine „E-Mail Injection“ machen. Dazu versucht man ganz einfach weitere Header-Informationen in die E-Mail zu schmuggeln.
Einzelne Header-Zeilen werden ja durch Zeilenumbrüche voneinander getrennt, also lassen sich weitere Header-Informationen einfach mit zusätzlichen Zeilenumbrüchen einschleusen. Ein typischer Formmailer besteht aus den Feldern Betreff, Name des Absenders, der Absender-Mail und natürlich dem eigentlichen Text. Um jetzt neben der Absender-Mail noch eine Kopie zu verschicken, braucht man das Formular nur mit dem Header Field cc: oder bcc: „vergiften“. Statt „the_new_strangeness@yahoo.de“ gebe man also „the_new_strangeness@yahoo.de\ncc:nospam@gmx.net“ ein. Dadurch hat man eine Kopie an die E-Mail-Adresse nospam@gmx.net geschickt.
Zwar sind die Felder des Formmailers nur für einzeiligen Text gedacht, aber wie man sieht hält das niemanden davon ab, weitere Zeilenumbrüche einzufügen. Auch ein Wechsel von GET auf POST wird da nicht viel bringen und Lösungen wie Captchas schrecken Besucher ab und sind vom Standpunkt der Barrierefreiheit aus gesehen eine Katastrophe.
Um den Formmailer vor derlei Missbrauch wirksam zu schützen, muss geprüft werden, ob Zeilenumbrüche vorhanden sind, um diese ggf. zu entfernen. Einzeilige Felder wie Betreff, Name des Absenders und Absender-Mail sollten also unbedingt geprüft werden. Der eigentliche E-Mail-Text darf aber Zeilenumbrüche beinhalten.
Darüber hinaus sollte man sich auch nicht auf Felder, die als readonly oder disabled gekennzeichnet sind, verlassen. Diese Sperre lässt sich leicht umgehen und so hat ein Spammer leichtes Spiel, wenn man die E-Mail-Adresse des Empfängers auf diese Weise zu schützen gedenkt. Man sollte die E-Mail-Adresse des Empfängers also unbedingt „hart“ in den Quelltext eingeben und sich nicht auf die Werte der POST- oder GET-Variable verlassen.
Der Spammer oder der Spambot versuchen auszutarieren, ob ein Formmailer für Spammissbrauch anfällig ist. Dazu schreibt er eine E-Mail-Adresse mit ihrer Domain in die Mail und versendet eine Kopie an seine eigene Wegwerf-E-Mail-Adresse. Wenn die E-Mail bei dem Spammer ankommt, dann weiß er, dass sich der Formmailer für Spam missbrauchen lässt. Daraufhin wird über ihren Formmailer Werbung an den Rest der Menschheit verschickt, natürlich nicht mit der E-Mail-Adresse des Spammers, sondern mit ihrer. Ein weiteres starkes Indiz für ein Spamattacke ist also, dass der Absender krude E-Mail-Adressen mit ihrer Domain erfindet. Bei meiner Domain sähe dass dann z.B. so aus: the6482@antikoerperchen.de, e7294@antikoerperchen.de, roth6453@antikoerperchen.de, arconi1639@antikoerperchen.de etc.
Ein weiterer Hinweis auf Spam ist natürlich, wenn in der E-Mail Header Fields auftauchen, die gerne für Spam verwendet werden. Mit cc: und bcc: lassen sich z.B. ganz wunderbar Kopien und damit auch Spam an andere verschicken.
Mein Mini-Spamfilter arbeitet ähnlich wie SpamAssassin nach einem Score-System. Für Auffälligkeiten an der E-Mail, die auf Spam hindeuten, werden Punkte vergeben. Wenn ein bestimmter Punktestand erreicht ist, dann geht der Filter davon aus, dass es sich um Spam handelt. Mein Spamfilter hat 3 Abstufungen:
Eine E-Mail wird als möglicher Spam betrachtet. Die E-Mail wird mit einem Warnhinweis versehen.
Eine E-Mail ist höchstwahrscheinlich Spam. Die E-Mail wird mit einem deutlichen Hinweis auf Spambefund versehen.
Die E-Mail ist Spam und wird nicht versendet.
Und so sieht es im E-Mail-Programm aus, wenn eine E-Mail als Spam erkannt wurde..
Wann welche Stufe eintritt und welche Meldung ausgegeben werden soll, lässt sich leicht im Quelltext einstellen.
Der Filter besteht aus 2 Funktionen. Welche einfach in den bestehenden PHP-Quelltext des Formmailers kopiert werden. Vor der Zeile, in der die E-Mail im Quellcode abgeschickt wird, muss ein Quellcode-Block eingefügt werden:
$spamlevel+=spamlevel_ermitteln( $name, "check_linebreaks", "remove_linebreaks", $name ); $spamlevel+=spamlevel_ermitteln( $absender_mail, "check_linebreaks", "remove_linebreaks", $absender_mail ); $spamlevel+=spamlevel_ermitteln( $betreff, "check_linebreaks", "remove_linebreaks", $betreff ); $spamlevel+=spamlevel_ermitteln( $text, "no_linebreak_check", "no_linebreak_remove", $text ); spamlevel_verarbeitung($spamlevel, $betreff, $text);
Die Variablennamen $betreff, $absender_mail, $name und $text müssen nur noch an die Variablennamen ihres Formmailers angepasst werden und die Zeile $meine_domain="antikoerperchen.de"; sollte ebenfalls auf ihre Domain geändert werden.