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.