nils-hero: Sicherer PHP Code?

Hallo,

Mal eine allgemeine Verständnis-Frage:

Ist der nachfolgende Code sicher - abgesehen von einer fehlenden Prüfung auf Länge des im Feld eingegebenen Textes? Wenn nein, wie würde ein Angreifer hier vorgehen? Und wie müsste man es richtig machen?

[code lang = php]
<?php

$inhalt = "";
$quelle = "text.xml";

if (isset($_POST['textfeld'])) {
   $inhalt = stripslashes($_POST['textfeld']);
   $dateihandler = fopen($quelle, "w+");
   fwrite($dateihandler, $inhalt);
   fclose($dateihandler);
}

else {
   $dateihandler = fopen("text.xml", "r");
   $inhalt = fread($dateihandler, filesize($quelle));
}

$inhalt = stripslashes($inhalt);

echo '<?xml version="1.0" encoding="utf-8" ?>';

?>
[/code]~~~html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>

<head>
      <title>XML aus Formular in Datei speichern</title>
   </head>

<body>
      <form action="formular-xml-in-datei.php" method="post">
         <textarea name="textfeld" rows="10" cols="50"><?php echo $inhalt ?></textarea>
         <input type="submit" value="Abschicken" />
      </form>
   </body>

</html>

  
Gruß, Nils

-- 
[Bookmarks](http://del.icio.us/nilslindemann)
  1. Hallo,

    Mal eine allgemeine Verständnis-Frage:

    Ist der nachfolgende Code sicher - abgesehen von einer fehlenden Prüfung auf Länge des im Feld eingegebenen Textes? Wenn nein, wie würde ein Angreifer hier vorgehen? Und wie müsste man es richtig machen?

    Hallo,

    $inhalt = stripslashes($_POST['textfeld']);

    sieht nach magic quotes aus. Schreib dir für das Entfernen der Slashes eine Funktion die du später auslagern kannst. Da jagst du dann erstmal alles was per POST oder GET kommt durch. So kommst du nicht durcheinander und brauchst später nicht mehr dran denken ob nun noch Slashes da sind oder nicht mehr.

    <textarea name="textfeld" rows="10" cols="50"><?php echo $inhalt ?></textarea>

    <?PHP echo htmlspecialchars($inhalt); ?> wäre hier richtig.

    Ob dein Code dann sicher ist, kann ich nicht beurteilen,.
    Ich arbeite so gut wie nie mit Dateien ;)

    Grüße, Matze

    1. Hallo,

      @ EKKi
      @ Matze

      htmlspecialchars():
      Warum steht im Quelltext der Seite '&lt;xml&gt;&lt;/xml&gt;', aber in text.xml '<xml></xml>' ? Ich wandle das doch gar nicht zurück ?! Wird da eine implizite Rückwandelung vorgenommen?

      Gruß, Nils

      1. Hallo,

        Warum steht im Quelltext der Seite '&lt;xml&gt;&lt;/xml&gt;', aber in text.xml '<xml></xml>' ? Ich wandle das doch gar nicht zurück ?! Wird da eine implizite Rückwandelung vorgenommen?

        weil html_special_chars() aus z.B. "<" "&lt;" macht.
        Und zum Beispiel aus dem Anführungszeichen " das "&quot;".
        Wenn jetzt in deiner Variable steht 'Horst schließt eine </textarea>',
        dann steht in deinem Textfeld:
        <textarea name="textfeld" rows="10" cols="50">Horst schließt eine </textarea></textarea>.
        Was da wohl jetzt der Browser denkt?

        Wenn du das ganze nach html_special_chars() anschaust, steht dort
        <textarea name="textfeld" rows="10" cols="50">Horst schließt eine &lt;/textarea&gt;</textarea>.
        Damit kann dann auch der Browser was anfangen.
        Soweit klar?

        Grüße, Matze

        1. Mahlzeit,

          Wenn jetzt in deiner Variable steht 'Horst schließt eine </textarea>',
          dann steht in deinem Textfeld:
          <textarea name="textfeld" rows="10" cols="50">Horst schließt eine </textarea></textarea>.
          Was da wohl jetzt der Browser denkt?

          Viel schlimmer:

          Wenn $BOESEWICHT ursprünglich folgendes eingegeben hatte: '</textarea><script type="text/javascript"> ganz_furchtbar_boeser_JS_code; </script><textarea>'

          Dann würde das PHP-Skript nach dem Auslesen aus der Datei folgendes ausspucken:

          <textarea name="textfeld" rows="10" cols="50"></textarea><script type="text/javascript"> ganz_furchtbar_boeser_JS_code; </script><textarea></textarea>.

          Der Browser stellt wunderbar gültigen HTML-Code dar ... und - oh Schreck! - führt böses Javascript aus ...

          MfG,
          EKKi

          --
          sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
          1. Hallo @all,

            Viel schlimmer:

            Wenn $BOESEWICHT ursprünglich folgendes eingegeben hatte: '</textarea><script type="text/javascript"> ganz_furchtbar_boeser_JS_code; </script><textarea>'

            Dann würde das PHP-Skript nach dem Auslesen aus der Datei folgendes ausspucken:

            nein, Nils hat ja vorgesorgt, siehe meine Analyse:

            Nach dem if-else-Konstrukt hat $inhalt nun den Inhalt:

            '</textarea><script type="text/javascript"> ganz_furchtbar_boeser_JS_code; </script><textarea>'

            Nils läßt darüber erneut stripslashes laufen und erhält somit

            '<textarea><script type="textjavascript"> ganz_furchtbar_boeser_JS_code_jetzt_kaputt_weil_nicht_mehr_genug_slashes; <script><textarea>'

            <textarea name="textfeld" rows="10" cols="50"><textarea><script type="textjavascript"> ganz_furchtbar_boeser_JS_code_jetzt_kaputt_weil_nicht_mehr_genug_slashes; <script><textarea></textarea>.

            Der Browser stellt wunderbar gültigen HTML-Code dar ... und - oh Schreck! - führt böses Javascript aus ...

            Ist der HTML-Code wirklich noch gültig?
            <textarea> in <textarea>, nicht geschlossen, in <textarea> zweimal <script> geöffnet, einmal mit einer seltsamen Typ-Angabe ...

            Bringt hier Nils unbewußt den Angriff zu Fall? Versuchen die Browser den kaputten Code irgendwie zu interpretieren? Will ich's wirklich wissen? ...

            Freundliche Grüße

            Vinzenz

            1. Mahlzeit,

              Nils läßt darüber erneut stripslashes laufen und erhält somit

              Nein, erhält er nicht.

              Ist der HTML-Code wirklich noch gültig?

              Ja.

              <textarea> in <textarea>, nicht geschlossen, in <textarea> zweimal <script> geöffnet, einmal mit einer seltsamen Typ-Angabe ...

              Nein.

              Bringt hier Nils unbewußt den Angriff zu Fall?

              Nein, weil stripslashes() AFAIK - entgegen seinem Namen - nur Backslashes () entfernt ... :-)

              MfG,
              EKKi

              --
              sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
              1. Hallo EKKi,

                Nein, weil stripslashes() AFAIK - entgegen seinem Namen - nur Backslashes () entfernt ... :-)

                da hab' ich letzte Woche ganz schönen Blödsinn verzapft.

                Freundliche Grüße

                Vinzenz

  2. Mahlzeit,

    Ist der nachfolgende Code sicher - abgesehen von einer fehlenden Prüfung auf Länge des im Feld eingegebenen Textes? Wenn nein, wie würde ein Angreifer hier vorgehen? Und wie müsste man es richtig machen?

    Wenn ich das richtig sehe, schreibst Du den Inhalt des <textarea> in eine Datei? Und beim Auslesen wird genau das, was in der Datei steht, ins <textarea> geschrieben?

    Was sollte $BOESEWICHT also daran hindern, in das <textarea> validen HTML-Code (ggf. mit <script>-Tags und ein bisschen Javascript angereichert) einzugeben und zu schauen, was bei der Ausgabe so passiert?

    Ich vermisse ganz extremst "htmlentities()" bei der Ausgabe ...

    MfG,
    EKKi

    --
    sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
    1. echo $begrüßung;

      Ich vermisse ganz extremst "htmlentities()" bei der Ausgabe ...

      Warum vermisst du diese Funktion und nicht htmlspecialchars()?

      echo "$verabschiedung $name";

  3. Hallo Nils,

    Ist der nachfolgende Code sicher

    er ist vor allen Dingen fehlerhaft, Matze und EKKi haben Dich schon auf die
    wichtigsten Unterlassungen hingewiesen, auf die ich nicht mehr als nötig
    eingehen werde:

    [code lang=php]
    <?php

    $inhalt = "";
    $quelle = "text.xml";

    if (isset($_POST['textfeld'])) {
       $inhalt = stripslashes($_POST['textfeld']);

    // Du verläßt Dich hier darauf, dass magic_quotes auf on stehen.
    // Verwende lieber die im PHP-Handbuch aufgeführte Version.
    // Grundsätzlich ist es eine gute Idee, Rohdaten abzuspeichern.

    // Nehmen wir nun an, $inhalt sei von der Slashitis geheilt ...

    $dateihandler = fopen($quelle, "w+");
       fwrite($dateihandler, $inhalt);
       fclose($dateihandler);
    }

    else {
       $dateihandler = fopen("text.xml", "r");
       $inhalt = fread($dateihandler, filesize($quelle));

    // ... nehmen wir an, der Inhalt der Datei leide nicht an Slashitis,
    // wozu auch?

    }

    // Du hast also hier eine Variable $inhalt, die nicht unter Slashitis leidet.
    // Diese enthält möglicherweise wunderbar erforderliche Slashes, z.B. für
    // Linkziele, Kommentare :-), Verzeichnisangaben oder im Text als
    // Trennzeichen, was auch immer.

    $inhalt = stripslashes($inhalt);

    // Oh je, Slashes, die da sein sollten, sind nun weg :-(
    // $inhalt leidet jetzt nicht an Slashitis, dafür an akutem Slashmangel.

    [...]

    <form action="formular-xml-in-datei.php" method="post">

    // in der folgenden Zeile ist die Ausgabe der Variablen dem Kontext, (X)HTML
    // gemäß zu maskieren: echo html_special_chars($inhalt)

    <textarea name="textfeld" rows="10" cols="50"><?php echo $inhalt ?></textarea>

    [...]

    Freundliche Grüße

    Vinzenz

    1. Hallo

      <form action="formular-xml-in-datei.php" method="post">

      // in der folgenden Zeile ist die Ausgabe der Variablen dem Kontext, (X)HTML
      // gemäß zu maskieren: echo html_special_chars($inhalt)

      Nur der Vollständigkeit halber: htmlspecialchars() vollkommen _mit_ohne_ Unterstrichen!

      Tschö, Auge

      --
      Die Musik drückt aus, was nicht gesagt werden kann und worüber es unmöglich ist zu schweigen.
      (Victor Hugo)
      Veranstaltungsdatenbank Vdb 0.2
  4. echo $begrüßung;

    Ist der nachfolgende Code sicher

    "Sicherheit" ist kein Zustand, und schon gar kein absoluter. Definiere, was du unter Sicherheit verstehst.

    Abgesehen von dem bereits Bemängelten (falsches Ent-Magic-Quoten, Kontextwechsel zu HTML nicht beachtet):

    $dateihandler = fopen($quelle, "w+");

    fopen() liefert im Fehlerfall ein false zurück.

    fwrite($dateihandler, $inhalt);

    Ein false ist aber kein gültiges Argument für fwrite. Das will eine Ressource haben und beklagt sich anderenfalls. Viele andere Funktionan reagieren ebenfalls unterschiedlich im Gut- und im Fehlerfall. Sorge dafür, dass dein Script stets alle vorkommenden Fälle behandelt und entsprechend reagiert. Schlage im Handbuch nach, was eine Funktion in welchem Fall zurückliefert und ignoriere dies nicht. Fehlermeldungen können wichtige Hinweise enthalten, sowohl für dich als Programmierer als auch für Angreifer, verraten sie doch Interna, die normalerweise verborgen bleiben. Auf Verborgenes sollte man sich zwar nie verlassen, aber präsentieren muss man es ja nun auch nicht gleich.

    echo "$verabschiedung $name";

  5. Hallo,

    Danke an alle für die Tips, ich fauler Kerl will jetzt nicht jedem einzeln antworten (:

    Ich hab das Script erweitert, und eine flexiblere Funktion für die Backslashes hinzugefügt, entnommen dem PHP-Manual. Die Entfernung von Javascript Tags etc. hab ich der Übersichtlichkeit halber weggelassen, das mache ich dann, wenn ich das xml bearbeite oder mit nem regulären Ausdruck.

    Ich kriege allerdings trotz des try-catch-Blockes ein 'Warning' wegen fopen, wenn die txt.xml fehlt und ich das Dokument frisch aufrufe (also ohne gesetztes $_POST["textfeld']), warum ?!

    Ausserdem, ist folgendes korrekt? Text, der z.b. als '&lt;text&gt;&lt;/text&gt;' in der Textarea steht und dann abgeschickt wird, wird wieder zurückgewandelt in die eigentlichen Zeichen, entsprechend der im Dokument verwendeten Zeichencodierung und kommt dann beim verarbeitenden Script als z.B. '<text></text>' an.

    Hier der Code, falls ihn jemand gebrauchen kann/bewerten will.

      
    <?php  
      
    echo '<?xml version="1.0" encoding="utf-8" ?>';  
      
    $inhalt   = "";  
    $quelle   = "text.xml";  
    $post_sauber = transcribe($_POST);  
      
    /*  
     * transcribe() is taken (and slightly changed) from http://de.php.net/get_magic_quotes_gpc,  
     * where php at kaiundina dot de postet it on 03-Feb-2005 01:18  
     *  
     * */  
      
    function transcribe($aList, $aIsTopLevel = true) {  
      
        $t    = split("\.",phpversion(),2);  
        $version_php = $t[0];  
      
        switch ($version_php) {  
            case "4":  
                $gpcList = array();  
                $isMagic = get_magic_quotes_gpc();  
      
                foreach ($aList as $key => $value) {  
                    $decodedKey = ($isMagic && !$aIsTopLevel)?stripslashes($key):$key;  
                    if (is_array($value)) {  
                        $decodedValue = transcribe($value, false);  
                    } else {  
                        $decodedValue = ($isMagic)?stripslashes($value):$value;  
                    }  
                    $gpcList[$decodedKey] = $decodedValue;  
                }  
                return $gpcList;  
      
            case "5":  
                $gpcList = array();  
                $isMagic = get_magic_quotes_gpc();  
      
                foreach ($aList as $key => $value) {  
                    if (is_array($value)) {  
                        $decodedKey = ($isMagic && !$aIsTopLevel)?stripslashes($key):$key;  
                        $decodedValue = transcribe($value, false);  
                    } else {  
                        $decodedKey = stripslashes($key);  
                        $decodedValue = ($isMagic)?stripslashes($value):$value;  
                    }  
                    $gpcList[$decodedKey] = $decodedValue;  
                }  
                return $gpcList;  
      
            case "6":  
                return $aList; // in PHP 6 gibt es keine magic-quotes mehr ...  
      
        }  
      
    }  
      
      
      
      
    try{  
        if (isset($post_sauber['textfeld'])){  
            if (trim($post_sauber['textfeld'])==""){  
                $inhalt = "Stille...";  
            }  
            else {  
                $inhalt = $post_sauber['textfeld'];  
                $dateihandler = fopen($quelle, "w+");  
                if (!$dateihandler) throw new Exception('konnte '.$quelle.' nicht zum Schreiben öffnen...');  
                else {  
                    fwrite($dateihandler, $inhalt);  
                    fclose($dateihandler);  
                }  
            }  
        }  
      
      
        else {  
            $dateihandler = fopen($quelle, "r");  
            if (!$dateihandler) throw new Exception('konnte '.$quelle.' nicht zum Lesen öffnen...');  
            else $inhalt = fread($dateihandler, filesize($quelle));  
        }  
    }  
    catch(Exception $e){  
        $inhalt = $e->getMessage();  
    }  
      
      
    ?>
    ~~~~~~html
      
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  
           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
      
    <html>  
      
    <head>  
    <title>XML aus Formular in Datei speichern</title>  
    </head>  
      
    <body>  
    <form action="formular-xml-in-datei-v2.php" method="post">  
    <textarea name="textfeld" rows="10" cols="50"><?php echo htmlspecialchars($inhalt); ?></textarea>  
    <input type="submit" value="Abschicken" />  
    </form>  
    </body>  
      
    </html>  
    
    

    Gruß, Nils

    1. echo $begrüßung;

      Ich hab das Script erweitert, und eine flexiblere Funktion für die Backslashes hinzugefügt, entnommen dem PHP-Manual.

      Im Allgemeinen ist es nicht notwendig, die Keys zu entslashen. Normalerweise verwendet man ja selbst solche kritischen Zeichen in den Keys nicht. Wenn irgendwer falsche Keys einschleust, hat das auch keine Auswirkungen, wenn man nur auf bekannte Keys zugreift. Mit foreach durch $_POST/$_GET durchzulaufen und ungeprüft alles zu übernehmen, ist auch nicht das, was man mit wachem Verstand und Problembewusstsein macht. Es reicht also die einfache Variante des Example#2 von Disabling Magic Quotes.

      Ich kriege allerdings trotz des try-catch-Blockes ein 'Warning' wegen fopen, wenn die txt.xml fehlt und ich das Dokument frisch aufrufe (also ohne gesetztes $_POST["textfeld']), warum ?!

      try-catch wirkt nur für Exceptions. Eine solche werfen aber die PHP-Funktionen nicht. Nur in einigen neueren Extensions, die sich auch objektorientiert verwenden lassen, gibt es mitunter Exceptions. Da du das Ergebnis nun auswertest, kannst du fopen() mit einem @ "dekorieren".

      Ausserdem, ist folgendes korrekt? Text, der z.b. als '&lt;text&gt;&lt;/text&gt;' in der Textarea steht und dann abgeschickt wird, wird wieder zurückgewandelt in die eigentlichen Zeichen, entsprechend der im Dokument verwendeten Zeichencodierung und kommt dann beim verarbeitenden Script als z.B. '<text></text>' an.

      Wenn der Text '<text></text>' in einem HTML-Kontext stehen soll, muss er wie von dir genannt notiert werden, damit der Browser ihn als Text und nicht als Code ansieht. HTML ist ja ebenso wie ein SQL-Statement eine Mischung aus Code und Daten. Deshalb muss man da besondere Vorkehrungen treffen, um das eine von dem anderen zu unterscheiden. Wenn Daten vom Browser zum Server gesendet werden, kümmert sich der Browser um eine kontextgerechte Behandlung (Kontext ist nun HTTP). Du bekommst davon normalerweise nichts mit, denn PHP entfernt die "Transportsicherung", bevor es $_POST und $_GET befüllt (und anschließend gegebenenfalls mit Magic Quotes verhunzt).

      $dateihandler = fopen($quelle, "w+");
                  if (!$dateihandler) throw new Exception('konnte '.$quelle.' nicht zum Schreiben öffnen...');
                  else {
                      fwrite($dateihandler, $inhalt);
                      fclose($dateihandler);
                  }

      Da du durch das Werfen der Exception im Fehlerfall diesen Abschnitt komplett verlässt, ist es nicht mehr notwendig, die Anweisungen im else-Block in einem solchen zu notieren. Bei erfüllter if-Bedingung wird dieser Zweig aufgrund der Exception sowieso nicht erreicht. Deshalb muss er nicht aus dem normalen Fluss augeklammert werden.

      fwrite() kann übrigens auch fehlschlagen, nämlich dann, wenn beim Schreiben der zur Verfügung stehende Platz ausgeschöpft wurde. In dem Fall gibt es auch ein false zurück. Ob ebenfalls eine PHP-Meldung ausgegeben wird, entzieht sich meiner Kenntnis.

      echo "$verabschiedung $name";

      1. Hallo wieder,

        Im Allgemeinen ist es nicht notwendig, die Keys zu entslashen. Normalerweise verwendet man ja selbst solche kritischen Zeichen in den Keys nicht. Wenn irgendwer falsche Keys einschleust, hat das auch keine Auswirkungen, wenn man nur auf bekannte Keys zugreift. Mit foreach durch $_POST/$_GET durchzulaufen und ungeprüft alles zu übernehmen, ist auch nicht das, was man mit wachem Verstand und Problembewusstsein macht. Es reicht also die einfache Variante des Example#2 von Disabling Magic Quotes.

        Alles gute Vorschläge, ich hab daher das Script nochmal umgeschrieben, s.u.

        Da du das Ergebnis nun auswertest, kannst du fopen() mit einem @ "dekorieren".

        Aha, war mir auch neu (Schreibe häufiger in Python).

        Wenn der Text '<text></text>' in einem HTML-Kontext stehen soll, muss er wie von dir genannt notiert werden, damit der Browser ihn als Text und nicht als Code ansieht. HTML ist ja ebenso wie ein SQL-Statement eine Mischung aus Code und Daten.
        Deshalb muss man da besondere Vorkehrungen treffen, um das eine von dem anderen zu unterscheiden.

        Leider zeigt der Firefox auch ohne das Wrappen mit htmlspecialchars() Tags in einem Textfeld 'korrekt' an, was m.E. eher irritiert, als hilft, wenn man das lernt.

        Wenn Daten vom Browser zum Server gesendet werden, kümmert sich der Browser um eine kontextgerechte Behandlung (Kontext ist nun HTTP). Du bekommst davon normalerweise nichts mit, denn PHP entfernt die "Transportsicherung", bevor es $_POST und $_GET befüllt (und anschließend gegebenenfalls mit Magic Quotes verhunzt).

        Für's Archiv: Ich hab das gerade mit UrlParams getestet und da hab ichs kapiert (glaub ich zumindest):

        Eine Zeichenkette in einem Textfeld (immer ohne die '') ...

        1. '<a href="http://www.de.selfhtml.org">Selfhtml</a>'

        ... bzw. mit htmlspecialchars() maskiert ...

        '&lt;a href=&quot;http://www.de.selfhtml.org&quot;&gt;Selfhtml&lt;/a&gt;'

        ... wird vom FF nach ...

        2. '%3Ca+href%3D%22http%3A%2F%2Fwww.de.selfhtml.org%22%3ESelfhtml%3C%2Fa%3E'

        ...umgewandelt, über http an den Server geschickt, wo php es zurückwandelt nach...

        3. '<a href="http://www.de.selfhtml.org">Selfhtml</a>'

        ... und es dann, *in die Tischkante beiß*, unter PHP 5 wie folgt, anders unter PHP 4 umwandelt in ...

        4. '<a href="http://www.de.selfhtml.org">Selfhtml</a>'

        ... was ich dann im PHP-Script wieder zurückwandle nach ...

        5. '<a href="http://www.de.selfhtml.org">Selfhtml</a>'

        ... und das war nur die Kommunikation von Client -> Server, *umfall*.

        Ich glaub ich hab das jetzt gecheckt... Danke soweit für die Hilfe (:

        ---

        Script, Version 3:

          
        <?php  
          
        echo '<?xml version="1.0" encoding="utf-8" ?>';  
          
        $inhalt   = "";  
        $quelle   = "text.xml";  
          
          
        /*  
         * Taken from Example 2 at http://php.net/manual/en/security.magicquotes.disabling.php  
         *  
         * */  
        if (function_exists("get_magic_quotes_gpc") and get_magic_quotes_gpc()) {  
          
            function stripslashes_deep($value)  
            {  
                $value = is_array($value) ?  
                array_map('stripslashes_deep', $value) :  
                stripslashes($value);  
          
                return $value;  
            }  
          
            $_POST = array_map('stripslashes_deep', $_POST);  
            $_GET = array_map('stripslashes_deep', $_GET);  
            $_COOKIE = array_map('stripslashes_deep', $_COOKIE);  
            $_REQUEST = array_map('stripslashes_deep', $_REQUEST);  
        }  
          
          
          
        try{  
            if (isset($_POST['textfeld'])){  
                if (trim($_POST['textfeld'])==""){  
                    $inhalt = "Stille...";  
                }  
                else {  
                    $inhalt = $_POST['textfeld'];  
                    $dateihandler = @fopen($quelle, "w+");  
                    if (!$dateihandler)  
                    throw new Exception('konnte '.$quelle.' nicht zum Schreiben öffnen...');  
                    if (!@fwrite($dateihandler, $inhalt))  
                    throw new Exception('konnte nicht in '.$quelle.' schreiben...');  
                    if (!@fclose($dateihandler))  
                    throw new Exception('konnte '.$quelle.' nicht schließen...');  
                }  
            }  
          
          
            else {  
                $dateihandler = @fopen($quelle, "r");  
                if (!$dateihandler)  
                throw new Exception('konnte '.$quelle.' nicht zum Lesen öffnen...');  
                if (!$inhalt = @fread($dateihandler, filesize($quelle)))  
                throw new Exception('konnte nicht aus '.$quelle.' lesen...');  
            }  
        }  
        catch(Exception $e){  
            $inhalt = $e->getMessage();  
        }  
          
        $inhalt = htmlspecialchars($inhalt);  
          
        ?>  
        
        
          
        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  
               "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
          
        <html>  
          
        <head>  
        <title>XML aus Formular in Datei speichern</title>  
        </head>  
          
        <body>  
        <form action="formular-xml-in-datei-v3.php" method="post">  
        <textarea name="textfeld" rows="10" cols="50"><?php echo $inhalt; ?></textarea>  
        <input type="submit" value="Abschicken" />  
        </form>  
        </body>  
          
        </html>  
        
        

        Gruß, Nils

        1. Hallo

          Für's Archiv: Ich hab das gerade mit UrlParams getestet und da hab ichs kapiert (glaub ich zumindest):

          Eine Zeichenkette in einem Textfeld (immer ohne die '') ...

          1. '<a href="http://www.de.selfhtml.org">Selfhtml</a>'

          ...

          ...umgewandelt, über http an den Server geschickt, wo php es zurückwandelt nach...

          3. '<a href="http://www.de.selfhtml.org">Selfhtml</a>'

          ... und es dann, *in die Tischkante beiß*, unter PHP 5 wie folgt, anders unter PHP 4 umwandelt in ...

          4. '<a href="http://www.de.selfhtml.org">Selfhtml</a>'

          Da bist du offensichtlich genau auf magic_quotes gestoßen. Schau mal in die php.ini beider Interpreterversionen.

            
          
          >     $_POST = array_map('stripslashes_deep', $_POST);  
          >     $_GET = array_map('stripslashes_deep', $_GET);  
          >     $_COOKIE = array_map('stripslashes_deep', $_COOKIE);  
          >     $_REQUEST = array_map('stripslashes_deep', $_REQUEST);  
          
          

          Das ist ja aus dem Beispielcode zu get_magic_quotes auf php.net. Ich frage mich immer, ob man immer alle vier der Arrays prüfen sollte, obwohl sie -bzw. einzelne- vielleicht im konkreten Fall garnicht existieren. Von der Existenz von GET und REQUEST sollte man ausgehen können, aber POST und COOKIE? Die müssen doch nicht vorhanden sein, oder?

          Tschö, Auge

          --
          Die Musik drückt aus, was nicht gesagt werden kann und worüber es unmöglich ist zu schweigen.
          (Victor Hugo)
          Veranstaltungsdatenbank Vdb 0.2
          1. Hallo,

            Das ist ja aus dem Beispielcode zu get_magic_quotes auf php.net.

            Rischtisch. Unerschöpfliche Quelle von Wissen und wie bei allen guten Seiten kann ohne Anmeldeprocedere lustig mitgeschnackelt werden (Für die schlechten gibts Auto Fill Forms).

            Ich frage mich immer, ob man immer alle vier der Arrays prüfen sollte, (...)

            nö, ich hab vergessen, das rauszunehmen. Die zweite Codezeile hätte gereicht. Und der Code von dort geht auch nur bis zum 'try', was ich auch hätte kennzeichnen können.

            Gruß, Nils

            1. Hallo

              Ich frage mich immer, ob man immer alle vier der Arrays prüfen sollte, (...)
              nö, ich hab vergessen, das rauszunehmen. Die zweite Codezeile hätte gereicht.

              Wenn nichts weiter ins Skript kommt, was weiterverarbeitet werden soll, wohl schon.

              Und der Code von dort geht auch nur bis zum 'try', was ich auch hätte kennzeichnen können.

              Naja, das kann aber auch jeder, der will, verifizieren.

              Tschö, Auge

              --
              Die Musik drückt aus, was nicht gesagt werden kann und worüber es unmöglich ist zu schweigen.
              (Victor Hugo)
              Veranstaltungsdatenbank Vdb 0.2
        2. echo $begrüßung;

          Eine Kleinigkeit noch.

          $inhalt = htmlspecialchars($inhalt);

          [viel später]

          <textarea name="textfeld" rows="10" cols="50"><?php echo $inhalt; ?></textarea>

          Es ist eindeutiger, wenn man die "Transportsicherung" erst beim "Versand" hinzufügt. Dass $inhalt bereits behandelt war, habe ich auf dem Weg bis zum echo $inhalt schon längst wieder vergessen. Ich sehe in dem zunächst <?php echo $inhalt; ?> nur ein Einfügen in einen Kontext, ohne selbigen behandelt zu haben. Das ist mir mittlerweile eine Reflex-Reaktion geworden. Nun muss ich mich erst in dem Quelltext rückwärts bewegen und sehen, wo $inhalt herkommt und was er beinhaltet.[1] Bei einem <?php echo htmlspecialchars($inhalt); ?> hingegen bleibt mein Alarmgöckchen angenehm ruhig.

          [1] In deinem Fall ist der Quelltext ja recht übersichtlich und ordentlich. Das hebt sich wohltuend von den anderen Codehaufen ab, die man sonst gelegentlich zu Gesicht bekommt. (z.B. meine allerersten Programmierversuche). Ein paar Kommentare hinzuzufügen, was mit den verschiedenen Codeblöcken erreicht werden soll, wäre noch empfehlenswert.

          echo "$verabschiedung $name";

          1. Schönen Sonntagmorgen,

            Es ist eindeutiger, wenn man die "Transportsicherung" erst beim "Versand" hinzufügt. Dass $inhalt bereits behandelt war, habe ich auf dem Weg bis zum echo $inhalt schon längst wieder vergessen.

            Gutes Argument -> übernommen.

            In deinem Fall ist der Quelltext ja recht übersichtlich und ordentlich. Das hebt sich wohltuend von den anderen Codehaufen ab, die man sonst gelegentlich zu Gesicht bekommt.

            *Stolz sei (und dedlfix nicht verrat, das Eclipse eine automatische Codeformatierung hat)*

            Ein paar Kommentare hinzuzufügen, was mit den verschiedenen Codeblöcken erreicht werden soll, wäre noch empfehlenswert.

            Ja, hab ich jetzt gemacht, aber ich poste das nicht nochmal, sind ja nur marginale Änderungen. Ich hab immer noch nicht eine Prüfung auf 'gefährliche' HTML-Tags drin und das von EisFux empfohlene flock() hab ich jetzt auch vorerst aussen vor gelassen. Ich werd das in ausführlicherer Version auf meiner Webseite diskutieren, da passt es auch besser hin als hier, wo der Code m.E. nur beispielhaft ausgeprägt sein sollte.

            So und jetzt lustig weitergecodet...

            Carpe Diem, Nils

            1. echo $begrüßung;

              Ich hab immer noch nicht eine Prüfung auf 'gefährliche' HTML-Tags drin

              Wenn du alle HTML-eigenen Zeichen, vor allem die aus der Benutzereingabe, beim Einfügen in den HTML-Kontext behandelst, hast du aus "gefährlichen HTML-Tags" harmlose Daten gemacht. Das ist aus sicherheitstechnischer Sicht ausreichend. Dass das Ergebnis bzw. die Benutzereingabe aus deiner Sicht ungewünschter Müll ist, steht auf einem anderen Blatt. Müll definiert sich nicht nur als HTML-Tags. Das können auch URL-Nennungen (auch ohne <a></a> und [url][/url] drumrum) oder eingschlafene Finger auf Buchstabentasten sein. Da hilft nur Moderation oder ein Ablehnen anhand von Mustererkennung.

              und das von EisFux empfohlene flock() hab ich jetzt auch vorerst aussen vor gelassen.

              Schutz gegen Mehrfachnutzung einer Ressource bei nebenläufigen Prozessen ist ein Thema, das oft übersehen wird. (So auch von mir in meinen vorigen Antworten.) Man merkt die Nebenläufigkeit und deren Auswirkungen im Labor meist nicht, weil man da der einzige Benutzer ist. Doch sobald mehrere Anwender gleichzeitig loslegen, ist die Wahrscheinlichkeit der gegenseitigen Beeinflussungen da. Es gibt übrigens einen SELFHTML-Aktuell-Artikel, der sich mit dem Sperren von Dateien beschäftigt.

              echo "$verabschiedung $name";

    2. (Hallo|Hi(ho)|Tag) nils-hero,

      Hier der Code, falls ihn jemand gebrauchen kann/bewerten will.

      <?php
              ...
              else {
                  $inhalt = $post_sauber['textfeld'];
                  $dateihandler = fopen($quelle, "w+");
                  if (!$dateihandler) throw new Exception('konnte '.$quelle.' nicht zum Schreiben öffnen...');
                  else {
                      fwrite($dateihandler, $inhalt);
                      fclose($dateihandler);
                  }
              }
          }

      else {
              $dateihandler = fopen($quelle, "r");
              if (!$dateihandler) throw new Exception('konnte '.$quelle.' nicht zum Lesen öffnen...');
              else $inhalt = fread($dateihandler, filesize($quelle));
          }
      ...

        
      Hat zwar nichts mit "Sicherheit" zu tun, wohl aber mit Datenintegrität:  
        
      Du öffnest im selben Script die selbe Datei ($quelle) sowohl zum Lesen ("r") als auch zum Schreiben ("w+"). Läuft das Script bspw. als Web-Anwendung, dann könnte es ja durchaus vorkommen, dass mehrere Instanzen deines Scripts versuchen, in die gleiche Datei zu schreiben, oder eine liest gerade, während eine andere schreibt. Das gibt irgendwann Datensalat. Also solltest du dich mit [flock()](http://de3.php.net/manual/de/function.flock.php) anfreunden und dieses nach den fopen()-Aufrufen einfügen. Ein Aufheben des Lockings ist nicht nötig, das wird auch mit fclose() erledigt.  
        
      MffG  
      EisFuX
      
      -- 
      [Nichts ist dem Zuwachs an Wissen förderlicher, als nach einer Antwort korrigiert zu werden.](http://community.de.selfhtml.org/zitatesammlung/zitat119)