Sven Rautenberg: OOP: Behandlung von Benutzereingaben für Konstruktor

Beitrag lesen

Moin!

Naja, ich hatte genau dort eine Sicherheitslücke vermutet.

Wenn eine Übergabe "SELECT * FROM tab WHERE 'name' = $name" eine Sicherheitslücke ist, könnte man ja vlt. auch mit new Benutzer($name); oder tuWas($name); etwas anstellen. Wie gesagt, ich habe dazu zu wenig Phantasie oder auch kriminelle Energie, aber möglicherweise kann man hier ja auch den Konstrukt beenden und anderen PHP-Code einfügen, wenn man es "unbehandelt" lässt. Speziell dazu habe ich nichts gefunden. Ob das jetzt an meinen Suchparametern gelegen hat oder es einfach kein Problem ist, vermochte ich nicht zu sagen.

Die Frage ist ja: WARUM ist das eine Sicherheitslücke?

Und die Antwort ist: In deinem SQL-Beispiel erzeugst du Programmcode, der ausgeführt wird. Neben den dir bekannten Bestandteilen (die konstant im String enthalten sind) fügst du außerdem noch einen unbekannten Bestandteil ein, nämlich die Benutzereingabe. Diese kann potentiell jeglichen Zeicheninhalt (inklusive aller nichtdruckbaren Bytes) enthalten, und in Kombination wird dein bekannter Codeteil plus der unbekannte Codeteil eventuell zu einem zerstörerischen oder zumindest unerwünschten Stück Software-Sourcecode, welcher dann von der SQL-Datenbank ausgeführt wird.

Deswegen gibt es zwei Methoden, wie man bei SQL solche Effekte verhindern kann:

1. Prepared Statements: Als SQL-"Programm" wird lediglich ein komplett konstantes Kommando mit ein paar Platzhaltern übergeben (es untersteht deiner vollständigen Kontrolle und tut deshalb nichts unerwartetes), und die Daten werden über einen separaten Datenkanal weitergereicht. Auf diese Weise ist garantiert, dass die Daten immer als Daten, nie jedoch als Programmteil interpretiert werden.

2. Alternativ kann man auch Escaping vornehmen, d.h. man sagt dem Datenbank-Client: Hier ist ein String, der hat evtl. komische Bytes und Zeichen - mach mal vor alles sowas eine Escape-Sequenz, damit der String in SQL nicht aus Versehen als Programmteil angesehen werden kann. Danach fügt man den abgesicherten String dann in's SQL ein und lässt es die Datenbank ausführen. Dabei sollte jetzt nichts mehr passieren.

Darf/sollte ich eine Postvariable unbearbeitetet an den Konstruktor übergeben?

Ja, darf man ohne Probleme, weil diese Variable nicht als Text mit weiterem Programmcode gemischt und dann interpretiert wird, sondern definitiv immer als Variable angesehen wird.

Sofern du nicht "eval()" mit dem Variableninhalt aufrufst, kann in den POST-Daten beliebiger Text drinstehen - er wird nie als PHP-Code interpretiert werden.

Allerdings gilt das natürlich nur solange, wie sichergestellt ist, dass tatsächlich keine Codeausführung möglich ist. Wenn dein Script den Inhalt der POST-Variablen z.B. in eine Textdatei speichert, und diese Textdatei könnte vom User her einen Namen bekommen, der auf ".php" statt ".txt" endet, und diese Datei ist auch zum Download per Webbrowser vorgesehen - dann wird der Inhalt der Datei mit großer Wahrscheinlichkeit als PHP-Code interpretiert und ausgeführt.

Die Gefahr lauert also immer dort, wo Daten unbeabsichtigt zu Code werden könnten. Und erweitert gilt dies auch für HTML, obwohl HTML ja keine Programmiersprache an sich ist, aber zum Beispiel Javascript enthalten kann. Wenn ein Angreifer Javascript in eine Seite einschleusen kann, ist das extrem schlecht. Und selbst wenn er "nur" normales HTML einschleusen kann, aber kein Javascript, reicht das oftmals schon aus, dass ein nichtsahnender User in der Annahme, er sei auf deiner Seite in Sicherheit, was Falsches zum Anklicken untergeschoben kriegt.

Den von dir verlinkten Artikel habe ich gelesen. Aber speziell zu der Problematik Daten an Klassen zu übergeben habe ich nichts gefunden. Aber zumindest hat er mich dazu motiviert, Daten nicht einfach unüberprüft zu übergeben und hier vorab nochmal nachzufragen ;-)

Wie gesagt: Das Weiterreichen von Variablen innerhalb eines Skripts ist generell ungefährlich, also darf jeglicher Bytemüll auch dem Konstruktor einer Klasse übergeben werden, ohne dass man an dieser Stelle Angst haben müsste.

Angst sollte man haben, wenn auf dem Weg von $_POST/_GET/_COOKIE/_SERVER hin zur letztendlichen Verwendung der Variablen in HTML, SQL, Javascript, CSS etc. nicht mehr nachvollzogen werden kann, ob in irgendeiner Zwischenschicht bereits eine Absicherung erfolgte, oder noch nicht. Und genau deshalb wird geraten, das zum letztmöglichen Zeitpunkt zu tun: Denn wenn man sich z.B. HTML-Code anschaut, in dem <?php echo $name ?> steht, dann will man nicht recherchieren, ob irgendwo vorher Escaping stattfand. Steht dort hingegen <?php echo htmlspecialchars($name) ?>, ist sonnenklar, dass hier Escaping stattfindet, man muss nichts suchen. (Ob es das korrekte Escaping ist, ist nochmal eine andere Frage, gerade bei HTML ist htmlspecialchars() ohne weitere Parameter nicht an jeder Stelle ausreichend.)

- Sven Rautenberg