Freitag, 23. Juni 2006

Sicheres Kontaktformular mit PHP - Spam verhindern

Viele Homepages besitzen ein Kontaktformular. Das man bei den meisten Formularen ohne Probleme Spam verschicken kann, wissen die wenigsten.

Das Problem ist, dass man unter Umständen den Mailheader verändern kann. Somit kann man dem Mailer ein wenig mehr unterschieben, als der Entwickler vorhatte und das Kontaktforumular wrid zum Spamformular...

Mailinjection Problembeschreibung und Lösungen

Auf vielen Homepages gibt es folgenden Programmcode, der eine Nachricht aus dem Kontaktformular versenden soll. Wir beschränken uns auf den Teil der die mail() Funktion von PHP aufruft.

Schlechter Code - so nicht!


Download Code!

  1.  
  2. mail('webmaster@fakedomain42.com', $_POST['subject'], $_POST['message'], 'FROM: '.$_POST['from']);
  3.  

Wir konzentrieren uns auf den letzten Parameter: 'FROM: '.$_POST['from'] - wo liegt genau das Problem? Ein Spammer oder eine andere böswillige Person kann jetzt Spam verschicken, indem er nicht nur seine Email einträgt, sondern auch noch etwas hinten dranhängt.

Spammer verwenden das Kontaktforumlar

Wenn jetzt folgendes in der $_POST['from'] steht: "spammer@spammingmakesmehappy.com \r\nBCC: spamopfer_1@kajh4ask.de; spamopfer_2@kajh4ask.de; spamopfer_1@kajh4ask.de; spamopfer_3@kajh4ask.de" werden Kopien der Nachricht an die Emailempfänger gesendet, welche nach dem BCC kommen. Somit kann man das Formular zum Spam versenden benutzen.

Lösungsansatz gegen Mailinjection

Download Code!

  1.  
  2. function spamSafe($text) {
  3.         return preg_replace("/(\n+|\r+|%0A|%0D)/i", '', $text);
  4. }
  5.  
  6. mail('webmaster@fakedomain42.com', $_POST['subject'], $_POST['message'], 'FROM: '.spamSafe($_POST['from']));
  7.  

Somit werden die Zeichen, die eine Mailinjektion ermöglichen mit nichts ersetzt und das Kontakformular kann nicht mehr zum Spammen verwendet werden.

Erklärung des Regex gegen Mailinjection

Der Reguläre Ausdruck setzt sich folgedendermaßen zusammen:

  • Die Slashs am Anfang und am Ende begrenzen den Regulären Ausdruck. Ist also eine Art Start, Stop Markierung.
  • Das Pipezeichen | in der Klammer bedeutet eine logisches Oder, also OR
  • \n ist ein Carriage Return
  • \r ist ein Line Feed
  • %0A ist die Hexadezimale Schreibweise für ein Linefeed LF
  • %0D ist die Hexadezimale Schreibweise für ein Cariage Return CR

Die Hexadezimale Schreibweise wird angewant, falls der geschickte String Urlkodiert ist. Urlkodierte Strings werden vom Server wieder in normale Zeichen zurückinterpretiert.

Fertige Mailklasse

Ich habe jetzt euch eine kleine Mailklasse zur einfachen Verwendung geschrieben: PHP-Mail-Klasse mit Spamschutz

Geschrieben von Mr.Foo in Sicherheit um 12:10
Kommentare (37) | Trackback (1)
Tags für diesen Artikel: Sicherheit
  1. Nicht gut
  2. Uninteressant
  3. Neutral
  4. Gut
  5. Sehr gut
Bewertung: 4 von 5, 1 Stimme(n) 252 Klicks

Trackbacks
Trackback für spezifische URI dieses Eintrags

Mailklasse in PHP mit Spamschutz
Aufgrund meines Artikels, sicheres Kontaktformular in PHP, habe ich eine kleine Mailklasse geschrieben, welche einfach zu benutzen ist und gegen Mailinjection-Attacken schützt.Download Code!class SimpleMailException extends Exception {} /**
Weblog: Mr. Foo
Aufgenommen: Jan 23, 18:46

Kommentare
Ansicht der Kommentare: (Linear | Verschachtelt)

Norbert - #1 - 29.06.2006 14:24 - (Antwort)

hallo - ich hätte gerne gewusst, wo ich die scripts für dieses mail-formular bekomme ?? - für eine schnelle antwort wäre ich dankbar. gruss norbert dollansky - info@it-netzwerk.de

Mr. Foo - #1.1 - 29.06.2006 15:40 - (Antwort)

Hallo Norbert,

was meinst du genau? Dieses Mailforumular gibt es nicht. Es ist fiktiver Beispielcode. Falls du aber ein komplettes Kontaktformularscript suchst kannst du mal unter hotscripts.com schauen. Da findest du sicher etwas.

Falls du noch Fragen hast, werde ich gerne Versuchen diese zu beantworten.

silvan - #2 - 01.02.2007 10:15 - (Antwort)

Besten Dank für das Veröffentlichen des Beispiel-Codes.

Mr. Foo - #2.1 - 01.02.2007 11:43 - (Antwort)

Hallo silvan,

freut mich, wenn der Quellcode dir geholfen hat. :-)

asdfasdf - #2.2 - 08.08.2007 14:16 - (Antwort)

das ist nur ein test

Chris - #3 - 15.02.2007 14:43 - (Antwort)

Sehr cool! Werd mich gleich mal an mein Script ransetzen...
Ist es sehr kompliziert ein solches Verfahren mit dem grafischen Sicherheitscode einzubauen? Mfg Chris

Gabe - #4 - 24.05.2007 19:57 - (Antwort)

Bei deinem RegExp fehlt der erste Delimiter: --> / preg_replace("/(\n+|\r+|%0A|%0D)/i", '', $text);

Mr. Foo - #4.1 - 31.05.2007 22:34 - (Antwort)

Hi Gabe,

vielen Dank für den Hinweis. Irgendwie ist der Slash beim letzten Editieren verlohrengegangen :-)

Frank - #5 - 17.06.2007 10:41 - (Antwort)

Hallo,

ich habe diese Funktion getestet, indem ich ein Formular mit dem oben genannten Absenderstring (spammer@spammingmakesmehappy.com \\r\\nBCC: spamopfer_1@kajh4ask.de; spamopfer_2@kajh4ask.de) gefüllt habe und diese Eingabe durch die spamSafe-Funktion schickte. In die habe ich noch Testausschriften eingebaut:

function spamSafe($text) {
echo $text . "";
$text = preg_replace("/(\n+|\r+|%0A|%0D)/i", '', $text);
echo $text . "";
return $text;
}

Dies sind die Ausschriften:
spammer@spammingmakesmehappy.com \\r\\nBCC: spamopfer_1@kajh4ask.de; spamopfer_2@kajh4ask.de
spammer@spammingmakesmehappy.com \\r\\nBCC: spamopfer_1@kajh4ask.de; spamopfer_2@kajh4ask.de

Ich sehe keinen Unterschied. Was mache ich falsch ? Was soll das preg_replace genau machen ?

Mr. Foo - #5.1 - 21.06.2007 22:07 - (Antwort)

Das liegt an der Option magic_quotes_gpc welche wahrscheinlich in der php.ini aktiviert ist. Die Funktion hat die Backslashes "escaped".

Das bedeutet, das beispielsweise Sonderzeichen, wie Zeilenumbrüche entwertet werden.

Du machst also nichts falsch in dem Sinne. Der reguläre Ausdruck in preg_replace sucht nach dem Zeilenumbruch, welcher aber nicht mehr gefunden wird, da der Backslash durch die oben genannte Funktionen entwertet wurde.

Webdesign - #6 - 05.11.2007 17:53 - (Antwort)

Die meisten Webdesigner machen die schönsten Kontaktformulare und vergessen leider immer wieder diese gegen Spam zu schützen. Wie oben beschrieben sind es gerade einmal zwei Zeilen PHP die, wenn sie implementiert würden tausende von Mailpostfächern vor SPAM verschonen würden.

Toller ZWEIZEILER !!
Holger

Mr. Foo - #6.1 - 05.11.2007 18:30 - (Antwort)

You are welcome :-)

pr online - #7 - 04.01.2008 04:38 - (Antwort)

Meiner meinung nach ist die beste Methode um Spam zu verhindern immer noch Captcha ;-)

White - #7.1 - 07.01.2008 22:46 - (Antwort)

Ist aber weder Barrierefrei noch unlösbar für Bots mittlerweile. Und für viele einfach nur nervig.
Simple Fragen oder genauere Überprüfung der Eingaben sind da wesentlich besser.

Mr. Foo - #7.1.1 - 08.01.2008 00:17 - (Antwort)

Es geht eigentlich darum eine sogenannte Header-Injection zu verhindern...

... aber seis drum :-)

White - #7.1.1.1 - 08.01.2008 17:41 - (Antwort)

Ist mir klar, meine Antwort war auf pr online bezogen ;-)

Robert - #8 - 02.02.2008 15:02 - (Antwort)

Hallo,

bin gerade dabei mich in die Materie einzuarbeiten ... Was spricht eigentlich dagegen, das Eingabefeld für die eMail Adresse mit z.B. maxlength="40" zu begrenzen?

MfG

Mr. Foo - #8.1 - 02.02.2008 15:11 - (Antwort)

Hallo Robert,

aus folgenden Gründen ist das nicht die beste Wahl:

1.) Emailadressen können länger sein.
2.) Diese Angabe ist nur eine Empfehlung für Browser
3.) Du versuchst wahrscheinlich einen Schutz Clienseitig zu implementieren. Das wäre der falsche Ansatz

Markus - #9 - 13.03.2008 16:27 - (Antwort)

Hey Sebastian,
sehr schöne sache. habe beim Einbinden allerdings noch ein Problem, vielleicht kannst du mir helfen, indem du mir kurz erläuterst, für was genau
"/(\n+|\r+|%0A|%0D)/i"
steht.

ganz speziell:
- warum beginnt der ausdruck mit einem /
- für was stehen die |
- für was steht %0A
?
gruß und danke,
markus

Mr. Foo - #9.1 - 13.03.2008 16:45 - (Antwort)

Hi,

ich habe oben den Artikel um die entsprechende Erklärung ergänzt.

Peter - #10 - 22.08.2008 10:06 - (Antwort)

Danke, genau nach sowas zum Einbauen hab ich gesucht.

Schöne Grüße.

Erich - #11 - 06.09.2008 04:31 - (Antwort)

Hallo Mr. Foo,

"spamSafe" muss auch für SUBJECT und MESSAGE verwendet werden, da sich darüber ebenfalls die Mail manipulieren lässt!

SUBJECT: "Hallo!%0ABcc:spammail@server.de"

Mr. Foo - #11.1 - 09.09.2008 11:44 - (Antwort)

Hi Erich,

vielen Dank.

Mir wäre es zwar neu, dass man auch über das Subject eine Headerinjection machen kann, aber ausschliessen möchte ich das nicht.

Ich werde aufjedenfall heute gleich mal überprüfen.

Erich - #11.1.1 - 11.09.2008 22:57 - (Antwort)

Eine Analyse der mir bekannten Injections habe ich online gestellt:
http://www.erich-kachel.de/?p=292

Du kannst übrigens die Injizierung eines "CC"-Parameters über den "Subject" mit diesem Code testen:

Download Code!

  1.  
  2. $subject = "Test\r\n \nCc: spam_mich@anderer-server.de\n";
  3. $message = 'Hallo';
  4.  
  5. mail('empfaenger@server.de', $subject, $message, 'From: sender@server.de');
  6.  

Mr. Foo - #11.1.1.1 - 24.01.2009 18:40 - (Antwort)

Du ich habe das übrigens in zich Variationen ausprobiert - leider konnte ich keine Headerinjection via Subject ausführen.

Danach habe ich mir den verantwortlichen PHP-Quellcode angeschaut:

Download Code!

  1. for(i = 0; subject_r[i]; i++) {
  2.         if (iscntrl((unsigned char) subject_r[i])) {
  3.                 SKIP_LONG_HEADER_SEP(subject_r, i);
  4.                 subject_r[i] = ' ';
  5.         }
  6. }

Wie man sehen kann durchläuft die For-Schleife das Subject. Wenn dann ein Steuerzeichen gefunden wird z.b CR, wird es durch ein Leerzeichen ersetzt.

Eine Mailinjection via Subject ist also unmöglich.

Michael - #12 - 17.11.2008 13:20 - (Antwort)

Für was steht eigentlich $text?

Mr. Foo - #12.1 - 17.11.2008 14:20 - (Antwort)

Das ist eine Variable, welche der Funktion übergeben wird.

Der Name ist ohne grössere Bedeutung gewählt worden.

Dennis - #13 - 23.01.2009 16:23 - (Antwort)

Ich habe versucht das in mein Formular einzubauen und bin als absoluter Laie gescheitert. Ich übergebe also diverse Variablen und speichere sie in $message. Jetzt will ich die kontakt-Variable prüfen, nach unerwünschten Zeichen, bcc und cc ausschließen sowie deine Funktion einbauen. Funktioniert aber nicht. Ich verstehe die preg_replace noch nicht so richtig und ob ich alles richtig übergebe und weiterverarbeite ist mir auch irgendwie unklar. Wäre nett, wenn einer helfen könnte. Solange probiere ich mal weiter.

Mr. Foo - #13.1 - 23.01.2009 16:57 - (Antwort)

Hi Dennis,

ohne deinen Code gesehen zu haben, wird es schwierig. :-)

Dennis - #14 - 23.01.2009 17:05 - (Antwort)

Download Code!

  1.  
  2. $message = $titel . "\n" . $autor . "\n" . $angaben . "\n" . $name . "\n" . $vorname . "\n" . $preis;
  3. $kontakt1 = preg_replace( "/[a-z0-9_-]+(\.[a-z0-9_-]+)*@([0-9a-z][0-9a-z-]*[0-9a-z]\.)+([a-z]{2,4}|museum)/i", "", $_POST['kontakt'] );
  4. /*
  5. $kontakt = preg_replace( "/(content-type:|bcc:|cc:|to:|from:)/im", "", $kontakt );
  6.  
  7. $message = preg_replace( "/(content-type:|bcc:|cc:|to:|from:)/im", "", $message );
  8. function spamSafe($kontakt) {
  9.         return preg_replace("/(\n+|\r+|%0A|%0D)/i", '', $_POST['kontakt'] );
  10. }*/
  11. mail("info@test.de","Nachricht von $_POST[vorname] $_POST[name]",$message . "\n" . $kontakt1);
  12.  


Hab diverses mal auskommentiert, da mir eine Fehlermeldung ausgegeben wird und hab jetzt vorne angefangen, aber bei der Überprüfung der e-Mail Adresse kann ich totalen Quatsch eingeben und die Mail kommt trotzdem an. Falls jetzt wieder kein Quellcode zu sehen ist, sagt mir bitte einer woran es liegen könnte.

Mr. Foo - #14.1 - 23.01.2009 18:53 - (Antwort)

Ich habe jetzt dir eine kleine Mailklasse geschrieben - siehe: http://mrfoo.de/archiv/741-Mailklasse-in-PHP-mit-Spamschutz.html

Versuch es am besten damit - wenn du damit Probleme hast - melde dich einfach wieder :-)

Dennis - #15 - 23.01.2009 20:18 - (Antwort)

Beim allem Respekt und ich finds wirklich wahnsinnig nett, aber ich habe mir ne simple HTML Seite programmiert mit einem simplen Formular. Das ganze hat mich gut zwei Wochen Zeit gekostet. Meine Programmierkenntnisse sind also wirklich arg beschränkt. Vielmehr muss meine Webseite auch gar nicht können. Das Formular soll nur Spam sicher sein. Nach stundenlangem lesen und diversen Versuchen, wollte ich eben eine Badword-Überprüfung, die Verhinderung von bcc und cc, einen Captcha und wenns ganz luxuriös werden soll einen Zeitstempel. Ich scheitere nun schon an Punkt 1 quasi. Das mit der Mailklasse überfordert mich also so dermaßen, dass ich vermutlich mindestens weitere zwei Wochen brauche, um das ansatzweise zu verstehen. Mir wäre also einfach nur ein Hinweis recht, warum das nicht funktioniert was ich gemacht habe und wie es funktionieren könnte und zwar so erklärt, dass es einer wie ich im fortgeschrittenen Alter auch versteht.

Vielen Dank!

Mr. Foo - #15.1 - 24.01.2009 18:10 - (Antwort)

Du solltest preg_match anstatt preg_replace verwenden. In deinem Code ersetzt du eine richtige Emailadresse mit nichts.

Richtig wäre der Code ungefähr so:

Download Code!

  1. $message = $titel . "\n" . $autor . "\n" . $angaben . "\n" . $name . "\n" . $vorname . "\n" . $preis;
  2. //Wenn eine richtige Emailadresse übergeben wurde.
  3. if(preg_match("/[a-z0-9_-]+(\.[a-z0-9_-]+)*@([0-9a-z][0-9a-z-]*[0-9a-z]\.)+([a-z]{2,4}|museum)/i", $_POST['kontakt'] )) {
  4.     mail("info@test.de","Nachricht von $_POST[vorname] $_POST[name]",$message . "\n".$_POST['kontakt'], 'From: '.$_POST['kontakt']);
  5. } else {
  6.     // Falsche Emailadresse
  7. }


Dennis - #16 - 25.01.2009 10:37 - (Antwort)

Hallo,

ich habe jetzt die function SpamSafe einbauen können und Sie scheint zu funktionieren. Ich würde auch gerne die Prüfung der e-Mail Adresse einbauen, ob überhaupt eine eingegeben wurde. Aber das Bsp. mit preg_match wirft bei mir Fehler aus. Gibt es da Konflikte? Kann ich die if-else preg_match in die function spamSafe einfach mit reinbauen? Ich probiers einfach mal, mal sehen was passiert.

Grüße

Mr. Foo - #16.1 - 25.01.2009 18:15 - (Antwort)

Das liegt an der Blogsoftware. Diese ersetzt aus irgendeinem Grund die Anführungszeichen in das HTML-Sonderzeichen quot; - ich bin gerade bei der Problemlösung.

Zwischenzeitlich kannst du den relevanten Code einfach nehmen und das " gegen das " ersetzen - dann sollte es gehen.

Mario - #17 - 06.12.2009 10:57 - (Antwort)

Hallo.

Wie kann muss ich meinen Code ändern, um diese Schutzzeilen mit drinne zu haben:

// eigentlicher Mailversandt

mail($admin, $subject1, $message1, "From: $Email");
mail($admin1, $subject1, $message1, "From: $Email");
mail($Email, $subject2, $message2, "From: $admin");

Kriege irgendwie das nicht eingebaut, denn bei meinem Script sieht das leider so wie oben angegeben aus.

Gruß,
mario

Mr. Foo - #17.1 - 07.12.2009 12:14 - (Antwort)

Download Code!

  1. $Email = spamSafe($Email);
  2. // der Rest deines Codes

PS. Kann der User die Variablen $subject2 und $message2 beinflussen? Wenn ja, kann er trotzdem das Script verwenden um Spam zu versenden.


Kommentar schreiben

Umschließende Sterne heben ein Wort hervor (*wort*), per _wort_ kann ein Wort unterstrichen werden.
Standard-Text Smilies wie :-) und ;-) werden zu Bildern konvertiert.
Die angegebene E-Mail-Adresse wird nicht dargestellt, sondern nur für eventuelle Benachrichtigungen verwendet.
Sie können [geshi lang=LANG][/lang] Tags verwenden um Quellcode abhängig von der gewählten Programmiersprache einzubinden
 
 

Mr. Foo

Sicheres Kontaktformular mit PHP - Spam verhindern

  • Homepage

Suche

Kategorien

  • C-Sharp (4)
  • Datenbank (25)
  • Delphi (2)
  • Entwicklung (33)
  • Flash (4)
  • Games (10)
  • Gutscheine (3)
  • Hardware (14)
  • HTML CSS (13)
  • Internet (79)
  • Java (30)
  • Javascript (22)
  • Linkdump (9)
  • Linux (93)
  • Low-Level (9)
  • Lua (8)
  • Musik (7)
  • Netzwerk (24)
  • New World Order (90)
  • Perl (3)
  • PHP (113)
  • Magento (5)
  • Symfony (3)
  • Zend Framework (7)
  • Probleme und Lösungen (26)
  • Python (22)
  • Ressourcen (22)
  • Sicherheit (76)
  • Software (46)
  • Sonstiges (43)
  • Own Stuff (34)
  • Spass (41)
  • Technik / Wissenschaft (3)
  • Tips (15)
  • Weisheiten (10)
  • Windows (22)


Alle Kategorien

Archive

  • September 2010
  • August 2010
  • Juli 2010
  • Das Neueste ...
  • Älteres ...

Blog abonnieren

  • XML RSS 0.91 feed
  • XML RSS 1.0 feed
  • XML RSS 2.0 feed
  • ATOM/XML ATOM 0.3 feed
  • ATOM/XML ATOM 1.0 feed
  • XML RSS 2.0 Kommentare

Tagcloud

Datenbank Entwicklung Internet Java Javascript Linux Lösung Netzwerk News New World Order PHP Problem Probleme und Lösungen Python Sicherheit Software Sonstiges Spass Update Windows

Kommentare

Jemand zu The following packages have been kept back
Do, 02.09.2010 03:00
Danke, mir hat es auch geholfen :-)
Droht Stuttgart 21 doch noch @ Video News zu Stuttgart 21 Abriss trotz Massenproteste
Mi, 01.09.2010 17:16
Das Bauprojekt Stuttgart 21 hat fr [...]
noura zu USB-Tastatur funktioniert nicht (beim Booten)
Mi, 01.09.2010 16:16
ich danke euch für dir tips. hatte [...]
Jo zu Node no longer exists Fehler in PHP
Di, 31.08.2010 19:48
Falls beispielsweise eine große Da [...]
Lilly zu Plugin-container.exe deaktivieren
So, 29.08.2010 20:28
braucht man diesen blöden Plugin-c [...]

Beliebte Einträge

  • Magento ist scheisse (123)
  • C compiler cannot create executables unter Debian (51)
  • Sicheres Kontaktformular mit PHP - Spam verhindern (37)
  • Option Bug im Internet Explorer bei Nutzung von innerHTML und Javascript (24)
  • Es konnte keine TCP/IP-Verbindung mit dem Host hergestellt werden (24)
  • Scheiss Linux - USB-Platte viel zu langsam (wenns mal funktioniert) (23)
  • Zend Studio - Javaw.exe lastet die CPU aus (21)
  • UML-Diagramme aus Java-Klassen generieren – Java2UML (20)
  • USB-Tastatur funktioniert nicht (beim Booten) (18)
  • CSS: Hover-Effekt beim Internet Explorer in Tabellen (17)

Umfragen


Archive
 

Kontakt