Entfernen, entfernen, entfernen… bis alles weg ist.
Ein Kommentar von Stefan Esser erinnerte mich an einen typischen Denkfehler bei der Entfernung von Zeichenketten aus einem String mit Hilfe von „preg_replace“. Es unterlief auch mir kürzlich ein solcher Fehler, deshalb möchte ich hier noch einmal mit einem Beispiel darauf hinweisen.
Möchte man aus einem Eingabestring bestimmte Zeichenketten entfernen weil sie vielleicht für den weiteren Verlauf des Skriptes schädlich sein könnten, kann verwendet werden:
<br />
<?php
$gefiltert = preg_replace("/(ENTFERNEN)/ims", "", $ungefiltert);
?><br />
Das funktioniert gut, solange die Eingabe sauber definierte Worte enthält:
<br />
Ich möchte das ENTFERNEN dieses Wortes ENTFERNEN.<br />
Ergibt mit der oben genannten Methode:
<br />
Ich möchte das dieses Wortes .<br />
Soweit alles wie erwartet. Was aber, wenn die Eingabe das betreffende Wort nicht in einer syntaktisch korrekten Weise enthält? Was ist das Ergebnis nach dem Filtern des folgenden Satzes?
<br />
Ich möchte das ENTFERNEENTFERNENN dieses Wortes EENTFERNENNTFERNEN.<br />
Das Ergebnis nach der Filterung ist dieses:
<br />
Ich möchte das ENTFERNEN dieses Wortes ENTFERNEN.<br />
Der Filter korrigiert die falsch geschriebenen Worte, die wir eigentlich entfernt haben wollten. So macht er aus dem Konstrukt ENTFERNEENTFERNENN durch das Löschen des mittleren Wortes wieder ein gültiges Wort. Da aber der Filter nach einem Durchlauf fertig ist, verbleibt im Eingabestring genau das, was wir entfernt haben wollten.
Die Filterung muss also so lange erfolgen, bis keine Ersetzung mehr statt findet, bis also Eingabe- und Ausgabestring gleich sind.
Und womit verdient diese Erkenntnis das Tag „Schwachstelle“? Du solltest für Sicherheitsdinge lieber einen positiven Regex nutzen der testet ob die Eingabe aus einem gültigem Set von Eingaben ist. Und preg_replace tut was es soll: in einer Eingabe alle vorkommen durch etwas anderes ersetzen, egal was dann hinteher noch rauskommt.
Weil es sich um eine wortwörtliche „schwache Stelle“ handelt ;)
Einen positiven Regex (aka: whitelist) empfehle ich bereits:
http://www.erich-kachel.de/?p=415
Überschrift: „Konzept eines Ausgabefilters auf Grundlage einer Whitelist“
Ja, preg_replace macht genau was es machen soll. Aber der PHP-Entwickler weißt es nicht. Er muss also beachten, dass nur ein Suchen-Ersetzen-Durchgang statt findet. Und genau darauf fokussiert der Beitrag.