Claudia: Mailscript schützen gegen Hack-Attacken???

Hallo,
ich kenne mich leider nicht sehr aus mit php. Ich mache lediglich
ein mailscript damit. Das funktioniert auch sehr gut. Nun möchte ich
gerne dieses ein wenig schützen hinsichtlich Hackattacken, Mehrfach-
senden usw. Dazu habe ich gewisse Zeichen escapt, funktioniert aber
nicht so richtig und ich weiß auch ehrlich gesagt nicht ob das die
richtige Methode ist.

Hier mal mein Script, ich hoffe einer kann mir dabei helfen.

<?php

urlencode ($nachricht);
$nachricht=str_replace("\r","\n",$nachricht);

$nameeingabe=preg_replace("\/.$?<>","",$nameeingabe);
$nachricht=preg_replace("\/.$?<>","",$nachricht);

$empfaenger = "meinname@meinedomain.de";

mail($empfaenger,"Formular: Nachricht von ".$nameeingabe,"
$nameeingabe machte folgende Angaben im Formular:
------------------------
Name:      $nameeingabe
E-Mail:    $email
Nachricht: $nachricht
------------------------

","From: $nameeingabe <$email>");

?>

Gruß
Claudia

  1. ich kenne mich leider nicht sehr aus mit php.

    <?php

    urlencode ($nachricht);
    $nachricht=str_replace("\r","\n",$nachricht);

    $nameeingabe=preg_replace("\/.$?<>","",$nameeingabe);
    $nachricht=preg_replace("\/.$?<>","",$nachricht);

    $empfaenger = "meinname@meinedomain.de";

    mail($empfaenger,"Formular: Nachricht von ".$nameeingabe,"
    $nameeingabe machte folgende Angaben im Formular:

    Name:      $nameeingabe
    E-Mail:    $email
    Nachricht: $nachricht

    ","From: $nameeingabe <$email>");

    ?>

      
    Hallo,  
      
    ist das wirklich dein komplettes Skript?  
    wo werden den die Variablen gesetzt?  
    Kannst du vielleicht dein komplettes Skript posten?  
    Und dann kann ich dir vielleicht Verbesserungen vorschlagen.  
      
    opa
    
    1. ist das wirklich dein komplettes Skript?
      wo werden den die Variablen gesetzt?
      Kannst du vielleicht dein komplettes Skript posten?
      Und dann kann ich dir vielleicht Verbesserungen vorschlagen.

      opa

      Die Variablen befinden sich in den Textfeldern. Ich habe ein Flash-
      formular.

      Das Formular funktioniert, nur das mit str_replace nicht oder muß
      man preg_replace benutzen?

      1. Mit preg_replace funktioniert es jetzt, juhu! :-)

      2. Hi!

        Das Formular funktioniert, nur das mit str_replace nicht

        Sicher?

        $nachricht=str_replace("\r","\n",$nachricht);

        Deine Funktion ersetzt \r durch \n.
        Bei den Zeilenumbrüchen handelt es sich vielleicht um \n (Unix-Style).
        In diesem Fall wäre gar nicht zu ersetzen.
        Handelt es sich bei den Zeilenumbrüchen um \r\n (Windows-Style), wird aus \r\n dann \n\n gemacht.
        Das hat dann doppelte Umbrüche zur Folge.
        Nur bei den alten Mac-Zeilenumbrüchen würde deine Funktion so arbeiten, wie sie sollte...

        $nameeingabe=preg_replace("\/.$?<>","",$nameeingabe);
        $nachricht=preg_replace("\/.$?<>","",$nachricht);

        Du mußt in jedem Fall Zeilenumbrüche aus den Eingaben rausfiltern.
        Besonders wichtig ist das bei $nameeingabe.
        Denn mit Zeilenumbrüchen werden Mailheader voneinander abgetrennt.
        Wenn du dein Script sichern willst, dann darf es nicht möglich sein, daß man der Mailfunktion ungewollte Mailheader andrehen kann.
        Damit könnte man dann dein Mailscript ein eine Spamschleuder verwandeln.
        Mehr dazu in der Wikipedia oder im Forumsarchiv.

        Ziemlich gefährlich sieht es auch aus, wie du deinen Mailtext übergibst.
        Es wäre viel sinnvoller, wenn du den Inhalt erst einmal ein einer Variablen speichern würdest und diese dann an die mail-Funktion übergibst.
        Deine Konstruktion sieht ziemlich gewagt aus...
        Was wäre denn jetzt, wenn in einer deiner Variablen in deinem Mailtext (nicht escapedte) Double-Quotes auftauchen würden?

        Schöner Gruß,
        rob

        1. Du mußt in jedem Fall Zeilenumbrüche aus den Eingaben rausfiltern.
          Besonders wichtig ist das bei $nameeingabe.
          Denn mit Zeilenumbrüchen werden Mailheader voneinander abgetrennt.
          Wenn du dein Script sichern willst, dann darf es nicht möglich sein, daß man der Mailfunktion ungewollte Mailheader andrehen kann.
          Damit könnte man dann dein Mailscript ein eine Spamschleuder verwandeln.

          Hab das jetzt so gemacht:

          $nameeingabe = preg_replace("/[\/.?<>]/", "", $nameeingabe);
          $email = preg_replace("/[\/?<>]/", "", $email);
          $nachricht = preg_replace("/[\<>]/", "", $nachricht);

          Wie mach ich das mit den Zeilenumbrüchen in nameeingabe?

          Es wäre viel sinnvoller, wenn du den Inhalt erst einmal ein einer Variablen speichern würdest und diese dann an die mail-Funktion übergibst.

          und wie mach ich das?

          Deine Konstruktion sieht ziemlich gewagt aus...
          Was wäre denn jetzt, wenn in einer deiner Variablen in deinem Mailtext (nicht escapedte) Double-Quotes auftauchen würden?

          Was waren nochmal Double-Quotes? *Kopfkratz*

          Danke und Gruß

          1. Du mußt in jedem Fall Zeilenumbrüche aus den Eingaben rausfiltern.

            Ist der Zeilenumbruch n? DoubleQuotes ". Also dann so?

            $nameeingabe = preg_replace("/[\<>.$?"\n]/", "", $nameeingabe);

            Es wäre viel sinnvoller, wenn du den Inhalt erst einmal ein einer Variablen speichern würdest und diese dann an die mail-Funktion übergibst.

            Das habe ich immer noch nicht verstanden...

            1. Hallo,

              $nameeingabe = preg_replace("/[\<>.$?"\n]/", "", $nameeingabe);

              Das sieht schon ganz in Ordnung aus. Ich bin mir aber nicht sicher, ob du wirklich alles Escapen musst und ob die Quotes um dem Rexexp wirklich sinnvoll sind.

              Es wäre viel sinnvoller, wenn du den Inhalt erst einmal ein einer Variablen speichern würdest und diese dann an die mail-Funktion übergibst.

              Das habe ich immer noch nicht verstanden...

              Das liegt vermutlich daran, dass du nicht viel Erfahrunf hast und du recht unsauber programmierst. Eigentlich dürften die inhalte von Formularen nämlich nicht direkt als Variable bereitgestellt werden (das ist nur bei Fehlkonfigurierten und/oder älteren Servern so) sondern müssen über ein globales Array wie $_GET[] oder $_POST[] abgefragt werden.

              Das sähe dann so z.B. stark vereinfacht so aus:

                
              var $nachricht=$_GET["Nachricht"]; //bzw. $_POST wenn du ein Form mit method=post verwendest  
              var $name=$_GET["Nameeingabe"]; //bzw. $_POST  
              $nachricht = preg_replace(...);  
              $name = preg_replace(...);  
              mail(...);  
              
              

              (Achtung, Ungetestet...)

              Jonathan

              1. Das sieht schon ganz in Ordnung aus. Ich bin mir aber nicht sicher, ob du wirklich alles Escapen musst und ob die Quotes um dem Rexexp wirklich sinnvoll sind.

                Lieber so?

                $nameeingabe = preg_replace('/[\<>.$?"\n]/', '', $nameeingabe);

                Eigentlich dürften die inhalte von Formularen nämlich nicht direkt als Variable bereitgestellt werden sondern müssen über ein globales Array wie $_GET[] oder $_POST[] abgefragt werden.

                Ich habe ein Flashformular in dem der Inhalt bzw. die Variablen
                an das php-script übergeben werden oder spielt das keine Rolle?

                So mach ich das in Flash:

                loadVariables("senden.php3", "", "POST");

                1. Hi!

                  So mach ich das in Flash:
                  loadVariables("senden.php3", "", "POST");

                  php3? Hat deine Datei wirklich die Endung .php3?
                  Du arbeitest doch nicht wirklich mit PHP3, oder?
                  Dann gäbe es nämlich gar kein $_POST.

                  Du holst dir also deine Variablen aus dem Flash-Formular.
                  Diese werden per POST an dein PHP-Script geschickt, ja?
                  Wenn das der Fall ist und du mit PHP 4 arbeitest, dann wird dein Hoster in der php.ini die Einstellung register_globals auf "on" gestellt haben.
                  Ansonsten würde dein Script nicht funktionieren...
                  Aber auch, wenn es so funktioniert, solltest du mit $_POST arbeiten - so wie Jonathan es beschrieben hat.

                  Schöner Gruß,
                  rob

                  1. php3? Hat deine Datei wirklich die Endung .php3?
                    Du arbeitest doch nicht wirklich mit PHP3, oder?
                    Dann gäbe es nämlich gar kein $_POST.

                    Funktioniert jetzt alles mit php3. Ist es besser alles
                    in php4 abzuspeichern?

                    Du holst dir also deine Variablen aus dem Flash-Formular.
                    Diese werden per POST an dein PHP-Script geschickt, ja?
                    Wenn das der Fall ist und du mit PHP 4 arbeitest, dann wird dein Hoster in der php.ini die Einstellung register_globals auf "on" gestellt haben.
                    Ansonsten würde dein Script nicht funktionieren...
                    Aber auch, wenn es so funktioniert, solltest du mit $_POST arbeiten - so wie Jonathan es beschrieben hat.

                    Werde ich mal versuchen mit $_POST.

                    1. Hiho!

                      Funktioniert jetzt alles mit php3. Ist es besser alles
                      in php4 abzuspeichern?

                      *nickt leicht entgeistert*
                      Ich meine natuerlich du sollst php 4 oder 5 benutzen. Welche Dateiendungen Du da benutzen musst weiss hier keiner ausser vielleicht Dir.

                      Werde ich mal versuchen mit $_POST.

                      brav

                    2. Hi!

                      Funktioniert jetzt alles mit php3. Ist es besser alles
                      in php4 abzuspeichern?

                      Wahrscheinlich ist es am besten, wenn du die Files einfach nur mit der Endung .php abspeicherst.

                      Werde ich mal versuchen mit $_POST.

                      Darum fragte ich eigentlich wegen dem PHP3.
                      $_POST gibt es nicht in PHP3. In PHP3 gibt es so einiges nicht...
                      PHP3 ist so unglaublich uralt, daß da eh niemand mehr mit arbeitet...
                      Aber auf deinem Server wird sicherlich auch kein PHP3 laufen, sondern du hast einfach nur die falsche Dateiendung genommen.
                      Der Server ist aber so eingestellt, daß halt auch Files mit der Endung .php3 geparst werden.

                      Schöner Gruß,
                      rob

                      1. Habe es nun so gemacht und funktioniert auch. Ist das mit $_POST
                        unbedingt erforderlich?

                        <?php

                        urlencode ($nachricht);
                        $nachricht=str_replace("\r","\n",$nachricht);

                        $nameeingabe = preg_replace('/[\<>.$?"\n]/', '', $nameeingabe);
                        $email = preg_replace('/[\<>$?"\n]/', '', $email);
                        $nachricht = preg_replace('/[\<>.$?"]/', '', $nachricht);

                        $empfaenger = "meinname@meinedomain.de";

                        $betreff = "Formular: Nachricht von " . $nameeingabe;

                        $nachrichtgesamt = "$nameeingabe machte folgende Angaben im Formular:\n\n";
                        $nachrichtgesamt.= "------------------------\n";
                        $nachrichtgesamt.= "Name:      $nameeingabe\n";
                        $nachrichtgesamt.= "E-Mail:    $email\n";
                        $nachrichtgesamt.= "Nachricht: $nachricht\n";
                        $nachrichtgesamt.= "------------------------\n";

                        mail( $empfaenger, $betreff, $nachrichtgesamt, "From: $nameeingabe <$email>" );

                        ?>

                        1. Hallo,

                          Habe es nun so gemacht und funktioniert auch. Ist das mit $_POST
                          unbedingt erforderlich?

                          Unbedingt erforderlich ist es nur, wenn es anders nicht geht. ;)

                          Da anscheinend die Variablen in der php3-Datei gesetzt werden, wäre deren Inhalt vielleicht interessant.

                          Jonathan

                          1. Unbedingt erforderlich ist es nur, wenn es anders nicht geht. ;)

                            Es geht, alles wird zufriedenstellend übertragen. :-)

                            Da anscheinend die Variablen in der php3-Datei gesetzt werden, wäre deren Inhalt vielleicht interessant.

                            Versteh ich nicht ganz. Es ist ein Flash-Kontaktformular wo die
                            Textfelder eine Variable haben. Übertragen wird es mit loadVariables
                            an die "senden.php"

                            Im Moment ist es so, daß alles funzt und wenn ich so fiese Steuer-
                            zeichen wie z.B.: < und > im Formular eintrage kommen diese nicht
                            bei mir an bzw. werden nicht bei mir angezeigt. Also alles in
                            Ordnung???

                            Gruß

                            1. Hallo,

                              Versteh ich nicht ganz. Es ist ein Flash-Kontaktformular wo die
                              Textfelder eine Variable haben. Übertragen wird es mit loadVariables
                              an die "senden.php"

                              Gut, ich habe noch nie mit Flashformularen gearbeitet, aber irgendwie müssen die Variablen ja in das PHP-Script reinkommen. Entweder ist bei dir register_globals auf on was generell nicht so gut ist, oder die Variablen kommen eben aus irgendeiner anderen Funktion.

                              Im Moment ist es so, daß alles funzt und wenn ich so fiese Steuer-
                              zeichen wie z.B.: < und > im Formular eintrage kommen diese nicht
                              bei mir an bzw. werden nicht bei mir angezeigt. Also alles in
                              Ordnung???

                              Ich denke schon. Sehr sauber programmiert sieht dein Script zwar jetzt nicht aus, aber ich denke von der Sicherheit ist es ganz in Ordnung.

                              Noch eine  Anmerkung: Ich hoffe, man kann auch anders mit dir in Kontakt treten als übers Flashformular. Nicht jeder hat Flash installiert oder will es installieren.

                              Jonathan

                              1. Guten Morgen Jonathan! :-)

                                Ich hab jetzt versucht alles umzusetzen mit dem Ergebnis, daß ich
                                jetzt keine vollständige Mail mehr bekomme. :-(
                                So sieht mein Mailscript zur Zeit aus:

                                senden.php

                                <?php

                                $nachricht=str_replace("\r","\n",$nachricht);

                                $nameeingabe = preg_replace('/[\<>.$?"\n]/', '', $nameeingabe);
                                $email = preg_replace('/[\<>$?"\n]/', '', $email);
                                $nachricht = preg_replace('/[\<>.$?"]/', '', $nachricht);

                                $empfaenger = "meinname@meinedomain.de";
                                $header = "From: $nameeingabe <$email>";
                                $header = "MIME-Version: 1.0\r\n";
                                $header = "Content-Type: text/plain; charset=iso-8859-1\r\n";

                                $betreff = "Formular: Nachricht von $nameeingabe";

                                $nachrichtgesamt = "$nameeingabe machte folgende Angaben im Formular:\n\n";
                                $nachrichtgesamt.= "------------------------\n";
                                $nachrichtgesamt.= "Name:      $nameeingabe\n";
                                $nachrichtgesamt.= "E-Mail:    $email\n";
                                $nachrichtgesamt.= "Nachricht: $nachricht\n";
                                $nachrichtgesamt.= "------------------------\n";

                                mail($empfaenger, $betreff, $nachrichtgesamt, $header);

                                ?>

                                1. Hi!

                                  Ich hab jetzt versucht alles umzusetzen mit dem Ergebnis, daß ich
                                  jetzt keine vollständige Mail mehr bekomme.

                                  Was heißt das?
                                  Wie sieht deine Mail aus?
                                  Wo wird abgebrochen?

                                  Bitte bemühe dich, brauchbare Fehlerbeschreibungen zu liefern.
                                  Wir sind keine Hellseher hier.
                                  Bitte liefere soviele Infos wie möglich, so daß man nicht jedesmal wieder nachfragen muß.

                                  Schöner Gruß,
                                  rob

                                  1. Hi,
                                    ich hab jetzt noch mal alles neu gemacht. Die Mail kommt an, alles
                                    wird übertragen.
                                    Das mit dem preg_replace hab ich probiert, funktioniert aber leider
                                    nicht.
                                    Wie mach ich das mit dem preg_replace?

                                    senden.php4

                                    <?php

                                    $text = str_replace("\r","\n",$_POST["nachricht"]);
                                    $text = urldecode($text);

                                    $empfaenger = "meinname@meinedomain.de";

                                    $betreff = "Formular: Neue Nachricht!";

                                    $mail_text = $_POST["nameeingabe"]." machte folgende Angaben im Formular:
                                    ------------------------

                                    ".$text."

                                    ------------------------
                                    E-Mail-Adresse: ".$_POST["email"]."";

                                    if(mail($empfaenger,$betreff,$mail_text,"From: ".$_POST["nameeingabe"]." <".$_POST["email"].">")) {
                                     echo "&txt_status=Erfolgreich gesendet.&";
                                    } else {
                                     echo "&txt_status=Fehler beim versenden.&";
                                    }

                                    ?>

                                2. Hallo,

                                  $header = "From: $nameeingabe <$email>";
                                  $header = "MIME-Version: 1.0\r\n";
                                  $header = "Content-Type: text/plain; charset=iso-8859-1\r\n";

                                  Hoer willst du bestimmt bei den beiden unteren Zeilen .= verwenden. Sonst weist du header nämlich immer was neues zu und überschreibst das alte...

                                  Jonathan

          2. Hi!

            und wie mach ich das?
            Das habe ich immer noch nicht verstanden...

            Du weißt nicht, wie du etwas in einer Variable speicherst?
            Also so sieht der Aufruf von mail() bei dir aus:

            mail($empfaenger,"Formular: Nachricht von ".$nameeingabe,"  
            $nameeingabe machte folgende Angaben im Formular:  
            ------------------------  
            Name:      $nameeingabe  
            E-Mail:    $email  
            Nachricht: $nachricht  
            ------------------------  
              
            ","From: $nameeingabe <$email>");
            

            Und so würde ich den Nachrichtentext nicht direkt im Funktionsaufruf von mail() unterbringen, sondern dieses erst in einer Variablen speichern und diese dann übergeben.
            In etwa so:

            $betreff = "Formular: Nachricht von " . $nameeingabe;  
              
            $nachricht = "$nameeingabe machte folgende Angaben im Formular:\n\n";  
            $nachricht.= "------------------------\n";  
            $nachricht.= "Name:      $nameeingabe\n";  
            $nachricht.= "E-Mail:    $email\n";  
            $nachricht.= "Nachricht: $nachricht\n";  
            $nachricht.= "------------------------\n";  
              
            mail( $empfaenger, $betreff, $nachricht, "From: $nameeingabe <$email>" );
            

            Natürlich könnte man dazu auch eine Heredoc-Bereich einsetzen.

            Und wie bereits geschrieben wurde:
            Niemals darfst du Variablen einfach ungeprüft übernehmen und deinen Funktionen übergeben.
            In deinem Script besteht hier die Gefahr eines Angriffes per E-Mail-Injektion.
            Daher mußt du (am besten mit deinen regulären Ausdrücken) zusehen, daß du eventuell gesendete Zeilenumbrüche (z.B. im Betreff) unschädlich gemacht werden. Ansonsten könnte man mail() eventuell ungewünschte Headerzeilen unterschummeln.
            Dadurch wäre es dann möglich, das Script zum Versand von Spam zu nutzen.

            Was waren nochmal Double-Quotes? *Kopfkratz*

            Double-Quotes sind die doppelten "Anführungszeichen".
            Naja, typografisch gesehen sind es eigentlich keine Anführungszeichen, auch wenn die dafür oft benutzt werden.
            Daher habe ich auch "Double-Quotes" geschrieben und nicht "Anführungszeichen".
            Single-Quotes hingegen, sind die einfachen 'Anführungszeichen' bzw. 'Hochkommata'.

            Schöner Gruß,
            rob

            1. Du weißt nicht, wie du etwas in einer Variable speicherst?

              Nö, ich hab nicht so viel Ahnung von php. :-) Ich mache nur das
              mailscript mit php.

              Und so würde ich den Nachrichtentext nicht direkt im Funktionsaufruf von mail() unterbringen, sondern dieses erst in einer Variablen speichern und diese dann übergeben.

              Jetzt hab ichs verstanden.

              Danke