Sap: Kontaktformualr sicher vor angriffen machen

Hi,
ich wollte wissen, wie ich mein Emailformular sicher vor Angriffen (Email Injection) mache.

  
<?php  
$empfaenger = 'xy@xy.de';  
$hidden	    = $_POST['hidden'];  
$name       = $_POST['name'];  
$email      = $_POST['email'];  
$betreff    = $_POST['betreff'];  
$nachricht  = $_POST['nachricht'];  
  
if(isset($_POST['abschicken']))  
{  
	if($_SESSION["hidden_alt"] != $_POST["hidden"])  
	{  
		$_SESSION["hidden_alt"] = $_POST["hidden"];  
		if(strlen($_POST['name'])>=2)  
		{	  
				if(strlen($_POST['betreff'])>=4)  
				{  
					if(strlen($_POST['nachricht'])>=10)  
					{  
                                             mail($empfaenger, $betreff, $nachricht, "From: $name <$email>")  
                                             or die("Die Mail konnte nicht versendet werden.<br>");  
                                             header("Location: kontakt.php");  
                                             exit;	  
					}  
					else  
					{  
					$fehler_nachricht = "<font color=red>Sie haben keine Nachricht verfasst.</font><br>";  
					}	  
				}  
				else  
				{  
				$fehler_betreff = "<font color=red>Geben sie den Betreff Ihrer Nachricht ein.</font><br>";  
		}  
		else  
		{  
		$fehler_name = "<font color=red>Geben sie ihren Namen ein.</font><br>";  
		}	  
	}  
}  
?>  

Ich hab daran gedacht, dass ich einfach vor den Variablen htmlspecialchars setze undzwar so:

  
<?php  
$empfaenger = 'xy@xy.de';  
$hidden     = htmlspecialchars($_POST['hidden']);  
$name       = htmlspecialchars($_POST['name']);  
$email      = htmlspecialchars($_POST['email']);  
$betreff    = htmlspecialchars($_POST['betreff']);  
$nachricht  = htmlspecialchars($_POST['nachricht']);  
?>  

Würde das klappen? Wenn ja würde das ausreichen oder sollte ich noch etwas hinzufügen? Wenn nein wie sollte ich es am besten machen?

Ich würde mich auf hilfreiche Beiträge freuen und bedanke mich im voraus.

MfG

Sap

  1. Hi,

    <?php
    $name       = $_POST['name'];
    $email      = $_POST['email'];
        mail($empfaenger, $betreff, $nachricht, "From: $name <$email>")
    ?>

      
    Ich bin mir nicht sicher ob das jetzt stimmt was ich jetzt schreibe,aber wenn man in $name oder $email einen Zeilenumbruch gefolgt von:  
    Cc: bla@example.com  
    macht koennte ich mir vorstellen, dass eine Mail an bla@example.com geschickt wird.  
    Ausserdem koennte man so wohl auch Attachments zu der Mail hinzufuegen oder aehnliches.  
      
    
    > Ich hab daran gedacht, dass ich einfach vor den Variablen htmlspecialchars setze undzwar so  
      
    Das ist der falsche Kontext.  
    Du willst ja den Text nicht als HTML anzeigen, sondern in einer Mail verwenden. Aber ich weiss leider auch nicht, was hier am besten waere.  
      
    Ob du die ersten 3 Parameter von mail() auch codieren musst weiss ich nicht, glaube aber eher nicht.  
      
    mfG,  
    steckl
    
  2. Hi,

    ich wollte wissen, wie ich mein Emailformular sicher vor Angriffen (Email Injection) mache.

    Hast du dich informiert, worauf E-Mail Header Injection basiert?

    Ich hab daran gedacht, dass ich einfach vor den Variablen htmlspecialchars [...]
    Würde das klappen?

    Nicht die Bohne; komplett falsche Baustelle (a.k.a. Kontext).

    Wenn nein wie sollte ich es am besten machen?

    Das Stichwort in das Suchmaschinenformular deiner Wahl eingeben.

    MfG ChrisB

    --
    Light travels faster than sound - that's why most people appear bright until you hear them speak.
  3. Hallo

    ich wollte wissen, wie ich mein Emailformular sicher vor Angriffen (Email Injection) mache.

    <?php
    $empfaenger = 'xy@xy.de';
    $hidden     = $_POST['hidden'];
    $name       = $_POST['name'];
    $email      = $_POST['email'];
    $betreff    = $_POST['betreff'];
    $nachricht  = $_POST['nachricht'];

      
    zuerst: Das ist unnötiges umkopieren. Die Variablen stehen dir ja in ihrer Rohform als $\_POST-Bestandteile eh zur Verfügung. Benutze sie also direkt.  
      
    [...Verarbeitung...]  
      
    
    > Ich hab daran gedacht, dass ich einfach vor den Variablen htmlspecialchars setze  
      
    Nein! Benutze htmlspecialchars \*nur\*, wenn du die behandelten Inhalte innerhalb von HTML ausgeben willst! \*Falls\* du eine HTML-Email senden willst, würde \*nur\* `$_POST['nachricht']`{:.language-php} dafür infrage kommen.  
      
    
    > Würde das klappen? Wenn ja würde das ausreichen oder sollte ich noch etwas hinzufügen? Wenn nein wie sollte ich es am besten machen?  
      
    Du solltest zuvörderst, vor jeglicher Verarbeitung, die übergebenen Werte prüfen. Zum Inhalt von `$_POST['hidden']`{:.language-php} kann niemand außer dir etwas sagen. `$_POST['name']`{:.language-php}, `$_POST['betreff']`{:.language-php} und `$_POST['nachricht']`{:.language-php} sind Freitext. Diesen kann man nicht ohne weiteres prüfen. Da zumindest (je nach Anwendungsfall) in `$_POST['nachricht']`{:.language-php} HTML oder anderer Code enthalten sein könnte, sollte man ihn dort auch belassen. Wenn du eine Reintextemail sendest, wird auch nur Text wie in einer TXT-Datei versendet. Da entsteht also kein Schaden. Für den Betreff und den Namen würde sich [striptags](http://www.php.net/striptags) anbieten.  
      
    Die Emailadresse (`$_POST['email']`{:.language-php}; offensichtlich die des Absenders) kann aber geprüft werden. Dabei ist zu beachten, dass der Aufbau einer Emailadresse sehr unterschiedlich sein kann. Sicher ist, dass es einen (variablen) lokalen Teil, das @-Zeichen und einen Domainnamen mit einem Punkt darinnen[1] gibt. Es gibt hier einen immer wieder mal kritisierten [Artikel](http://aktuell.de.selfhtml.org/artikel/programmiertechnik/email/), der einen regulären Ausdruck zusammenstückelt um auf eine gültige Emailadresse zu prüfen. So sollte (im PHP-Beispiel, gilt natürlich auch für andere Sprachen) im `$dom_tldpart`{:.language-php} (was \*mir\* (aber auch anderen) sofort in's Auge springt) `'[a-zA-Z]{2,5}';`{:.language-php} nach `'[a-zA-Z]{2,}';`{:.language-php} geändert werden, weil es auch längere TLDs als fünfzeichige gibt (z.B. 'museum'). Du kannst aber zumindest auf das '@' und den im folgenden Text (Domainteil) zu findenden '.' prüfen.  
      
    Wenn die Prüfungen erfolgreich absolviert sind, kannst du deine Email zusammenbauen und versenden.  
      
    [1] Das gilt zumindest für öffentliche Emailadressen.  
      
    Tschö, Auge  
    
    -- 
    Verschiedene Glocken läuteten in der Stadt, und jede von ihnen vertrat eine ganz persönliche Meinung darüber, wann es Mitternacht war.  
    Terry Pratchett, "Wachen! Wachen!"  
      
    [Veranstaltungsdatenbank Vdb 0.3](http://termindbase.auge8472.de/)
    
    1. Hallo

      $_POST['email'];
      $_POST['betreff'];

      Beide Angaben kommen in den Mailheader. Dort werden einzelne Angaben per "\r\n" (Windowszeilenumbruch) voneinander getrennt. Prüfe beide Angaben auf Zeilenumbrüche. Falsche Angaben (mit Zeilenumbruch) sind meist (eventuell *könnte* eine Mailadresse beim kopieren und einfügen einen Umbruch ohne folgenden Inhalt enthalten) bewusst gesetzt und als Angriff zu werten. Verwerfe die Angaben und damit die Mail.

      Tschö, Auge

      --
      Verschiedene Glocken läuteten in der Stadt, und jede von ihnen vertrat eine ganz persönliche Meinung darüber, wann es Mitternacht war.
      Terry Pratchett, "Wachen! Wachen!"
      Veranstaltungsdatenbank Vdb 0.3
      1. Hallo

        $_POST['email'];
        $_POST['betreff'];

        Beide Angaben kommen in den Mailheader. Dort werden einzelne Angaben per "\r\n" (Windowszeilenumbruch) voneinander getrennt. Prüfe beide Angaben auf Zeilenumbrüche. Falsche Angaben (mit Zeilenumbruch) sind meist (eventuell *könnte* eine Mailadresse beim kopieren und einfügen einen Umbruch ohne folgenden Inhalt enthalten) bewusst gesetzt und als Angriff zu werten. Verwerfe die Angaben und damit die Mail.

        Soll ich dann beide Angaben mit strpos überprüfen?
        if(strpos($email, "\n")||strpos($email, "\r"))
        {
          nicht weiterverarbeiten...
        }
        else
        {
          weiterverarbeiten...
        }

        Oder einfach mit preg_replace entfernen? (wie du gesagt hast kann ja ein versehen sein)
        $such = array("\n","\r");
        $ersetzung = "";
        preg_replace($such, $ersetzung, $email); //das gleich auch mit betreff

        Und noch ne Frage sagen wir mal ich will mehrere emails verschicken (cc,bcc).
        Wenn ich die Emailadressen mit einem Komma trenne muss ich sie später dann mit eine Zeilenumbruch ersetzen oder wie Funktioniert das?

        Gruß

        Sap

        1. Hello,

          Soll ich dann beide Angaben mit strpos überprüfen?
          if(strpos($email, "\n")||strpos($email, "\r"))
          {
            nicht weiterverarbeiten...
          }
          else
          {
            weiterverarbeiten...
          }

          Ja! Alle Daten, IP, X-FORWARED-FOR-IP (wenn vorhanden) und exakten Zeitpunkt registrieren und als potentielle kriminelle Handlung verfolgen!

          Oder einfach mit preg_replace entfernen? (wie du gesagt hast kann ja ein versehen sein)

          Nein, es kann kein Versehen sein, denn in ein Einzeiliges Input-Feld bekommt man aus Versehen keinen Zeilenumbruch hinein. Das geht nur absichtlich!

          $such = array("\n","\r");
          $ersetzung = "";
          preg_replace($such, $ersetzung, $email); //das gleich auch mit betreff

          Und noch ne Frage sagen wir mal ich will mehrere emails verschicken (cc,bcc).
          Wenn ich die Emailadressen mit einem Komma trenne muss ich sie später dann mit eine Zeilenumbruch ersetzen oder wie Funktioniert das?

          Da kommst Du in den Bereich, an den sich nur Programmierprofis heranwagen sollten. Wenn variante und/oder mehrere Empfänger zugelassen werden sollen, sollte sich der Absender auf jeden Fall authentifizieren müssen.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. Hallo

            Oder einfach mit preg_replace entfernen? (wie du gesagt hast kann ja ein versehen sein)

            Nein, es kann kein Versehen sein, denn in ein Einzeiliges Input-Feld bekommt man aus Versehen keinen Zeilenumbruch hinein. Das geht nur absichtlich!

            @Tom: Es kann aus Versehen sein. Die Emailadresse (um bei dem Beispiel zu bleiben) kann man schließlich auch von irgendwoher samt Umbruch kopieren. Das mag bei der Eingabe der eigenen Adresse unüblich sein, es ist aber grundsätzlich nicht ausgeschlossen.

            $such = array("\n","\r");
            $ersetzung = "";
            preg_replace($such, $ersetzung, $email); //das gleich auch mit betreff

            @Sap: Das Sucharray ist mMn die angemessene Lösung. Allerdings ist deine Form falsch. Es gibt Windows ("\r\n"), alte Mac-Systeme ("\r") und Unixiode samt MacOS-X ("\n"). *In dieser Reihenfolge* baust du das Array auf, damit es auch in dieser Reihenfolge geprüft wird. Mit deiner Reihenfolge ("\n","\r") würde ein Windowsumbruch zu zwei Umbrüchen, weil beide Fälle zutreffen. Der Aufbau gilt nicht nur für eine eventuelle Ersetzung, sondern auch für die Prüfung zum verwerfen der Anfrage.

            Und noch ne Frage sagen wir mal ich will mehrere emails verschicken (cc,bcc).
            Wenn ich die Emailadressen mit einem Komma trenne muss ich sie später dann mit eine Zeilenumbruch ersetzen oder wie Funktioniert das?

            Da kommst Du in den Bereich, an den sich nur Programmierprofis heranwagen sollten. Wenn variante und/oder mehrere Empfänger zugelassen werden sollen, sollte sich der Absender auf jeden Fall authentifizieren müssen.

            @Sap: Ich gehe mal davon aus, dass du einem Besucher die Möglichkeit gibst, mit dir in Kontakt zu treten. "To" ist deine festkodierte Adresse, als "Cc" würde der Absender (auch "From") durchgehen, "Bcc" sollte hier nicht auftreten. Wenn es aber mehrere "To", "Cc" oder "Bcc" geben sollte, wären das Kommagetrennte Listen *Ohne Umbruch* (außer dem abschließenden *Windowsumbruch* ("\r\n"), der zum nächsten Header überleitet).

            Tschö, Auge

            --
            Verschiedene Glocken läuteten in der Stadt, und jede von ihnen vertrat eine ganz persönliche Meinung darüber, wann es Mitternacht war.
            Terry Pratchett, "Wachen! Wachen!"
            Veranstaltungsdatenbank Vdb 0.3
            1. Hello,

              Nein, es kann kein Versehen sein, denn in ein Einzeiliges Input-Feld bekommt man aus Versehen keinen Zeilenumbruch hinein. Das geht nur absichtlich!

              @Tom: Es kann aus Versehen sein. Die Emailadresse (um bei dem Beispiel zu bleiben) kann man schließlich auch von irgendwoher samt Umbruch kopieren. Das mag bei der Eingabe der eigenen Adresse unüblich sein, es ist aber grundsätzlich nicht ausgeschlossen.

              Ich kenne allerdings keinen Browser, der das unterstützt, in einem einzeiligen Input-Feld einen Zeilenumbruch zu übernehmen. Dann müsste das Formular dafür schon eine Textarea bereitstellen.

              Hast Du das mal ausprobiert?

              @Sap: Das Sucharray ist mMn die angemessene Lösung. Allerdings ist deine Form falsch. Es gibt Windows ("\r\n"), alte Mac-Systeme ("\r") und Unixiode samt MacOS-X ("\n"). *In dieser Reihenfolge* baust du das Array auf, damit es auch in dieser Reihenfolge geprüft wird. Mit deiner Reihenfolge ("\n","\r") würde ein Windowsumbruch zu zwei Umbrüchen, weil beide Fälle zutreffen. Der Aufbau gilt nicht nur für eine eventuelle Ersetzung, sondern auch für die Prüfung zum verwerfen der Anfrage.

              Auch das ist nicht ganz richtig. Die HTTP-Applikation (der Browser) ist verpflichtet, Zeilenumbrüche als "\r\n" == CRLF (laut RFC) abzusenden und unvollständige ggf. zu ergänzen. Alle mir bekannten Browser auf allen Systemen tun dies auch. Die OS-interne Darstellung als "\n", "\r" oder "\r\n" haben damit nichts zu tun.

              Liebe Grüße aus dem z. Zt. regnerischen Oberharz

              Tom vom Berg

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
              1. Hi,

                Es kann aus Versehen sein. Die Emailadresse (um bei dem Beispiel zu bleiben) kann man schließlich auch von irgendwoher samt Umbruch kopieren. Das mag bei der Eingabe der eigenen Adresse unüblich sein, es ist aber grundsätzlich nicht ausgeschlossen.

                Ich kenne allerdings keinen Browser, der das unterstützt, in einem einzeiligen Input-Feld einen Zeilenumbruch zu übernehmen. Dann müsste das Formular dafür schon eine Textarea bereitstellen.

                Trotzdem halte ich es für weit über's Ziel hinausgeschossen, es wie du sagt gleich "als potentielle kriminelle Handlung verfolgen" zu lassen, wenn mal ein Request hereinkommt, der ein Zeilenumbruchzeichen an einer Stelle enthält, an der "man" es unter normalen Gegebenheiten nicht erwartet.

                Selbst wenn Absicht dahinter stecken sollte, sind unsere Strafverfolgungsbehörden m.E. mit weitaus wichtigeren Dingen schon mehr als genug ausgelastet.

                MfG ChrisB

                --
                Light travels faster than sound - that's why most people appear bright until you hear them speak.
                1. Hello,

                  Trotzdem halte ich es für weit über's Ziel hinausgeschossen, es wie du sagt gleich "als potentielle kriminelle Handlung verfolgen" zu lassen, wenn mal ein Request hereinkommt, der ein Zeilenumbruchzeichen an einer Stelle enthält, an der "man" es unter normalen Gegebenheiten nicht erwartet.

                  Selbst wenn Absicht dahinter stecken sollte, sind unsere Strafverfolgungsbehörden m.E. mit weitaus wichtigeren Dingen schon mehr als genug ausgelastet.

                  Und deshalb sollte man absichtlich wegsehen und sich den Vorgang nicht adäquat vermerken?
                  Wie will man eine Häufung derartiger Vorgänge feststellen, wenn man sie nicht entsprechend registriert und bewertet?

                  Das Netz ist zwar ein großer Spielplatz, aber manche Dinge muss man trotzdem ernst nehmen.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Hi,

                    Und deshalb sollte man absichtlich wegsehen und sich den Vorgang nicht adäquat vermerken?
                    Wie will man eine Häufung derartiger Vorgänge feststellen, wenn man sie nicht entsprechend registriert und bewertet?

                    Vermerken/Registrieren/Bewerten hat also bei dir unbedingt *Verfolgung* als potentielle kriminelle Handlung zu bedeuten?

                    Das Netz ist zwar ein großer Spielplatz, aber manche Dinge muss man trotzdem ernst nehmen.

                    Wenn du für dich Logging betreiben willst, gerne - aber die Strafverfolgungsbehörden mit solchen Bagatellen belasten, bitte nein.
                    Das wäre das Äquivalent zum Opi, der regelmäßig mit akkuraten Listen (inkl. Kennzeichen, Ort, Datum, "Tatort"-Foto) von Falschparkern auf der Wache auftaucht.

                    MfG ChrisB

                    --
                    Light travels faster than sound - that's why most people appear bright until you hear them speak.
    2. Es gibt hier einen immer wieder mal kritisierten Artikel

      Ich hab nur kurz reingesehen und TLD's dürfen dort nicht länger als 5 sein - "museum" fällt also raus. Hab auch nicht nachgesehen von wann das ist... also keine Ahnung, ob es die TLD schon gab, als der Artikel geschrieben wurde.

  4. Hi!

    ich wollte wissen, wie ich mein Emailformular sicher vor Angriffen (Email Injection) mache.

    Das setzt voraus, dass man die unsicheren Dinge kennt, verstanden hat wie sie wirken und daraufhin Maßnahmen ergreift, die einen Missbrauch verhindern.

    Ich hab daran gedacht, dass ich einfach vor den Variablen htmlspecialchars setze undzwar so:

    Da hast du nicht nur Wissenslücken bei Email-Headern. Schau dir meinen Artikel Kontextwechsel erkennen und behandeln an, der beinhaltet auch einen Abschnitt zu Email. Neben Email-Header-Injection ist auch noch die richtige Behandlung von Werten in anderen Headerzeilen erforderlich, beispielsweise Nicht-ASCII-Zeichen im Subject.

    Lo!

  5. Hallo,

    ich wollte wissen, wie ich mein Emailformular sicher vor Angriffen (Email Injection) mache.

    und warum stellst du diese Frage nicht in deinem Thread von gestern, in dem es ja schon um dieses Formular geht?
    Jetzt haben wir hier ein typisches Doppelposting, aber angesichts der schon vorhandenen guten Antworten wäre es nicht mehr sinnvoll, den Thread zu sperren.

    Bitte sei nächstes Mal so vernünftig und mach nicht wieder eine zweite oder dritte Baustelle auf.

    Ciao,
     Martin

    --
    Warum können wir heute so sicher sagen, dass Gott keine Frau sein kann?
    Weil dann nach "Es werde Licht" der nächste Satz "Wie sieht denn das hier aus?!" gewesen wäre.