julie: PHP Filter für Fließtext (Sonderzeichen üäöß)

Guten Morgen,

ich versuche gegen XSS Lücken per Formular zu arbeiten. PHP hat hier viele tolle filter für E-Mail, Int und co. Bei dem Filter für Fließtext scheite ich noch. Der nach meinem Testsetting am besten geignete ist: $text = filter_var($_REQUEST['text'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH);

Leider filtert er auch die Deutschen Sonderzeichen wie üöäß heraus. Sicher bin ich nicht die einzige mit dem Problem des Filterns. Wie habt ihr das Gelöst?

  1. Tach!

    ich versuche gegen XSS Lücken per Formular zu arbeiten. PHP hat hier viele tolle filter für E-Mail, Int und co.

    Filter sind aber kein Allheilmittel. Sie sollten nicht die einzige Waffe sein (wenn überhaupt). Das Problem an Filtern ist, dass sie auf die Eingangsdaten wirken, oder zumindest oftmals so angewendet werden. XSS ist aber ein Problem, das am Ausgang auftritt, da wo man Daten in Code (HTML etc.) einfügt.

    Filter arbeiten zudem zumeist destruktiv. Sie entfernen Inhalt aus den Nutzdaten. Beabsichtigt ist, dass es nur schädliche Daten trifft. Aber ob etwas schädlich ist, kann nicht der Filter allein bestimmen. Die Schädlichkeit ist immer abhängig vom Kontext. Und das ist der Kontext am Ausgang. HTML verwendet einige Zeichen für seine Syntax (<, >, …). Diese dürfen nicht einfach so im Text auftauchen. Aber sie können auch Bestandteil von gutartigem Text sein, den man eigentlich nicht wegfiltern möchte. Der eigentlich vorgesehene Weg ist deshalb Maskierung. Die Zeichen werden so gekennzeichnet, dass der Empfänger sie als Nutzdaten interpretiert und nicht als Code. Dieses Kennzeichnen ist kontextabhängig. Damit haben wir einen Interessenskonflikt, dass der Filter am Eingang den Kontext nicht kennt, und deshalb nur ganz allgemein Zeichen wegwerfen kann, statt sie für den Kontext am Ausgang passend zu maskieren. Oder der Filter beachtet lediglich einen einzelnen Kontext, und man hat dann die Daten versaut, wenn man sie in einen weiteren Kontext ausgeben möchte (Datenbank, Export in ein bestimmtes Dateiformat).

    Man kann sogar so weit gehen, dass man Filter am Eingang eigentlich gar nicht braucht, wenn man am Ausgang den Kontext beachtet und entsprechend maskiert.

    Bei dem Filter für Fließtext scheite ich noch. Der nach meinem Testsetting am besten geignete ist: $text = filter_var($_REQUEST['text'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH);

    Leider filtert er auch die Deutschen Sonderzeichen wie üöäß heraus. Sicher bin ich nicht die einzige mit dem Problem des Filterns. Wie habt ihr das Gelöst?

    Was ist denn das eigentliche Problem? Was genau soll den rausgefiltert werden und zu welchem Zweck?

    FILTER_FLAG_STRIP_HIGH filtert natürlich gemäß seiner Beschreibung alle Nicht-ASCII-Zeichen heraus. Wenn Umlaute und jede Menge anderer gutartiger Zeichen drinbleiben sollen, ist das die falsche Option. Es gibt stattdessen FILTER_FLAG_ENCODE_HIGH (encode statt strip), aber die Beschreibung sagt nicht, für welchen Kontext das Encoding erfolgt. Vermutlich ist das HTML und die Zeichen werden zu NCRs. Aber ist das generell und im speziellen Fall bei dir sinnvoll? Ist HTML der einzige Kontext, in den die gefilterten Daten eingefügt werden sollen? Eine Datenbank arbeitet jedenfalls mit Rohdaten besser als mit welchen, die für HTML aufbereitet sind. Und eine Datenbank hat ihren eigenen Kontext, für den andere Zeichen berücksichtigt werden müssen.

    HTML kennt jedenfalls nur Zeichen aus dem ASCII-Bereich, die eine syntaktische Bedeutung haben. Die "HIGH"-Zeichen müssen weder gefiltert noch als NCR kodiert werden. Und für HTML sollte man statt irgendwo am Eingang zu filtern lieber am Ausgang mit htmlspecialchars() maskieren. Dann sieht man auch, dass beim Einfügen der richtige Kontextwechsel beachtet wurde, und nicht vielleicht irgendwelche Eingangsdaten zu sanieren vergessen wurde.

    dedlfix.

    1. Hallo dedlfix,

      Vermutlich ist das HTML und die Zeichen werden zu NCRs.

      Äh - das musste ich erstmal googeln. Du meinst Numeric Character Reference, also ä -> &#228; bzw. &#xE4; ?

      Diese Filterei ist etwas, das einem von manchen IDEs auch geradezu aufgezwungen wird. Ich habe eine Weile mit Netbeans gearbeitet, und wenn man da PHP Code schrieb, der einen Wert aus irgendeinem Superglobal verwendete, ohne eine der filter-Funktionen dafür zu nutzen, bekam man direkt eine ganze Latte an Warnungen. Bloß damit Ruhe war, hat man dann FILTER_UNSAFE_RAW genommen, wenn man nichts filtern wollte.

      Dass eine IDE statt dessen warnen sollte, wenn man SQL Statements aus Rohdaten zusammenklebt, statt zu escapen oder eine PREPARE-Funktion zu verwenden, oder wenn man Variableninhalte ohne htmlspecialchars in den Ausgabestrom schreibt, ist wohl zu schwierig.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Lieber Rolf,

        oder wenn man Variableninhalte ohne htmlspecialchars in den Ausgabestrom schreibt,

        $doc = new DOMDocument;
        $doc->loadHTML(file_get_contents('template.html'));
        ...
        $html = $doc->saveHTML();
        echo $html; // Variableninhalt ohne htmlspecialchars
        

        Liebe Grüße

        Felix Riesterer

        1. Hallo Felix,

          dass eine Warnung nicht immer angemessen ist, will ich ja gar nicht bestreiten. Dein Beispiel zeigt vor allem die Schwierigkeiten auf, die solche IDE-Warnsysteme haben.

          Abgesehen davon - auch wenn das jetzt deutlich driftet - sollte man DOMDocument in dieser Form nicht mehr verwenden, bis irgendwer mal eine HTML 5 Version davon bereitstellt. $doc->saveHTML() erstellt ein HTML 4 Dokument. Man kann sich ein Element $x heraussuchen und mit $doc->saveHTML($x) ein HTML Fragment erzeugen, das man in einen ordentlichen HTML 5 Rahmen einsetzt, das ändert aber nicht den Fakt, dass HTML 5 Neuerungen, die loadHTML() nicht versteht, zu Warnings führen. Ich weiß nicht, was noch alles problematisch sein kann.

          Ein Thread auf stackoverflow, der das Thema diskutiert, empfiehlt html5-php. Der frühere Star der Show - html5lib-php - ist seit Jahren verwaist und html5-php scheint ein Abkömmling davon zu sein.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Lieber Rolf,

            Abgesehen davon - auch wenn das jetzt deutlich driftet - sollte man DOMDocument in dieser Form nicht mehr verwenden, [...] empfiehlt html5-php.

            ich nutze html5-php schon seit Jahren. Ja, die DOMDocument-Klasse ist spürbar in die Jahre gekommen. Insbesondere libxml ist daran schuld.

            Liebe Grüße

            Felix Riesterer

            1. Hallo,

              danke für die vielen Antworten. Ihr seid etwas vom Thema abgekommen. Die Frage war: [...]Was ist denn das eigentliche Problem? Was genau soll den rausgefiltert werden und zu welchem Zweck?[...] Ich habe ein PHP Formular für NutzerFeedback. Das Feedback wird in eine Json Datei gespeichert, und beim CMS Autoren Dashboard aufruf, wir der Inhalt angezeigt.

              Am liebsten wäre mir, wenn ich das Definieren könnte was "erlaubt" ist. Denn das ist das was der Mobilbrowser so an tippbaren Zeichen vorgibt. a-z A-Z 0-9 öäüßÖÄÜß !"§$%&/()=?*'#+:_,;><@€|

              Gibt es hier eine Lösung

              Danke Julie

              1. Tach!

                Ich habe ein PHP Formular für NutzerFeedback. Das Feedback wird in eine Json Datei gespeichert, und beim CMS Autoren Dashboard aufruf, wir der Inhalt angezeigt.

                Ja, aber was ist denn daran problematisch? Ein Json-Encoder weiß doch, wie korrektes JSON zu erzeugen ist, sonst wäre er kaputt. Und beim Ausgaben von Daten muss sowieso der Kontextwechsel beachtet werden. Ich kann den Grund nicht erkennen, warum am Eingang bestimmte Zeichen herausgefiltert werden müssen.

                Am liebsten wäre mir, wenn ich das Definieren könnte was "erlaubt" ist.

                Alles sollte erlaubt sein, solange es keinen fachlichen Grund gibt, denn technisch sehe ich keinen Grund, weil man kontextgerecht maskieren kann.

                Gibt es hier eine Lösung

                Anscheinend nicht mit Filter-Funktionen, aber einfaches Ersetzen aller nicht in der Liste stehenden Zeichen durch Leerstring würde gehen. Ein RegExp mit negierter Zeichenklasse wäre eine Möglichkeit.

                dedlfix.

                1. @@dedlfix

                  Gibt es hier eine Lösung

                  Anscheinend nicht mit Filter-Funktionen, aber einfaches Ersetzen aller nicht in der Liste stehenden Zeichen durch Leerstring würde gehen. Ein RegExp mit negierter Zeichenklasse wäre eine Möglichkeit.

                  Den Absatzt verstehe ich nicht.

                  Du hattest die Lösung doch schon genannt: Nichts filtern. Daten bei der Ausgabe entsprechend behandeln.

                  Warum weichst du das auf und schickst julie doch noch auf die falsche Fährte?

                  😷 LLAP

                  --
                  “When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down ‘happy.’ They told me I didn’t understand the assignment, and I told them they didn’t understand life.” —John Lennon
                  1. Tach!

                    Warum weichst du das auf und schickst julie doch noch auf die falsche Fährte?

                    Ich bin ja nicht ihr Vormund, wenn sie partout auf ihrem Ansatz besteht, soll sie damit glücklich werden.

                    dedlfix.

                    1. @@dedlfix

                      Warum weichst du das auf und schickst julie doch noch auf die falsche Fährte?

                      Ich bin ja nicht ihr Vormund, wenn sie partout auf ihrem Ansatz besteht, soll sie damit glücklich werden.

                      Ich glaub nicht, dass sie damit glücklich wird. Das kann man auch in aller Deutlichkeit so sagen.

                      😷 LLAP

                      --
                      “When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down ‘happy.’ They told me I didn’t understand the assignment, and I told them they didn’t understand life.” —John Lennon
              2. @@julie

                Am liebsten wäre mir, wenn ich das Definieren könnte was "erlaubt" ist.

                Das ist einfach: Erlaubt ist alles. Text, Emoji, …

                Gibt es hier eine Lösung

                Ja, und die hat @dedlfix auch schon genannt.

                😷 LLAP

                --
                “When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down ‘happy.’ They told me I didn’t understand the assignment, and I told them they didn’t understand life.” —John Lennon
      2. @@Rolf B

        Vermutlich ist das HTML und die Zeichen werden zu NCRs.

        Äh - das musste ich erstmal googeln. Du meinst Numeric Character Reference, also ä -> &#228; bzw. &#xE4; ?

        Hier im Forum oft verlinkt. Sehr oft. Verwendung von Zeichen-Escapes in Markup und CSS

        Wirklich so oft, dass es micht genervt hatte, dass es den Artikel nicht auf deutsch gab und ich mich rangesetzt hab, den zu übersetzen. (Viele andere sollten folgen.)

        Das war 2010. Als er dann übersetzt war, hier im Forum oft verlinkt. Sehr oft.

        😷 LLAP

        --
        “When I was 5 years old, my mother always told me that happiness was the key to life. When I went to school, they asked me what I wanted to be when I grew up. I wrote down ‘happy.’ They told me I didn’t understand the assignment, and I told them they didn’t understand life.” —John Lennon
        1. Hallo Gunnar,

          mag ja sein. Aber in meinem informationsimprägnierten Schädel war diese Abkürzung trotzdem nicht angekommen.

          Übrigens rät w3.org frecherweise von der Verwendung deiner Übersetzung ab, weil sie veraltet sei. Unter anderem ist die einleitende Nussschale neu.

          Rolf

          --
          sumpsi - posui - obstruxi