SQL-Injection und Cross-Site Scripting
heinetz
- programmiertechnik
Hallo Forum,
ich habe vor Jahren mal eie PHP/MySQL-Website programmiert ud bin
heute damit konfrontiert worden, die Seite auf Sicherheitslücken zu überprüfen. Jetzt frage ich mich, wie das am effektivsten geht.
Wie gehe ich am besten vor? Gibt es wirklich funktionierende Tools
oder Services, die man nutzen kann oder muss ich mir jede mögliche Interaktion mit der MySQL-DB ansehen und einfach alles was aus $_GET
oder $_POST kommt mit mysql_real_escape_string versehen, um SQL-Injection
zu verhindern?
Ein wesentlicher Paramter ist die immer vorhandene $site_id, aufgrund der
der Content aus meiner MySQL-DB ausgelesen wird.
danke für Tipps und
beste gruesse,
heinetz
Hallo!
Wie gehe ich am besten vor?
Am effektivsten wäre eine Validierung der Eingaben, sprich, ob das, was per $_POST oder $_GET Übergebene der erwarteten Eingabe entspricht.
Brauchbar hierfür wären zum Beispiel Reguläre Ausdrücke und Funktionen wie is_numeric() und Ähnliche.
Zusätzlich dazu ist ein mysql_real_escape_string() natürlich auch nicht unangebracht.
Liebe Grüße aus Norddeutschland.
Hi!
Am effektivsten wäre eine Validierung der Eingaben, sprich, ob das, was per $_POST oder $_GET Übergebene der erwarteten Eingabe entspricht.
Das kann effektiv sein, wenn man die Eingabemöglichkeiten auf eine sehr geringe, überschaubare und garantiert in allen Fällen "ungefährliche" Auswahl von Zeichen reduziert. So ein Vorgehen kann aber auch völlig unbrauchbar/unanwendbar sein. Nicht immer kann man dem Anwender das Verwenden bestimmter Zeichen verbieten, nur weil man sich selbst eine kontextgerechte Behandlung, die sich oft auf einen Maskierungsfunktionsaufruf beschränkt, sparen will.
Brauchbar hierfür wären zum Beispiel Reguläre Ausdrücke und Funktionen wie is_numeric() und Ähnliche.
Brauchbar kann alles ein, aber was davon sinnvoll ist, muss jeweils im konkreten Fall entschieden werden.
Lo!
Hallo!
Brauchbar kann alles ein, aber was davon sinnvoll ist, muss jeweils im konkreten Fall entschieden werden.
Stimmt. Ich denke, wir brauchen spezifischere Informationen, um genauere Aussagen machen zu können.
Liebe Grüße aus Norddeutschland.
Hi!
Wie gehe ich am besten vor? Gibt es wirklich funktionierende Tools oder Services, die man nutzen kann oder muss ich mir jede mögliche Interaktion mit der MySQL-DB ansehen und einfach alles was aus $_GET oder $_POST kommt mit mysql_real_escape_string versehen, um SQL-Injection zu verhindern?
Zum einen bringt es nichts, stur alles mit mysql_real_escape_string() zu behandeln. Das muss schon noch kontextabhängig passieren: Zahlen im (My)SQL-Statement.
Und dann wäre die Frage zu klären, wie ein Tool feststellen kann, dass ein Angriff erfolgreich war oder nicht. Das müsste dann schon eins sein, das eine Menge Anwendungsfälle beherrscht. Billig wäre das dann vermutlich nicht.
SQL-Injection ist auch nur eine Angriffsmöglichkeit. Vergiss nicht alle anderen Ausgaben auf Beachtung des Kontextwechsels zu prüfen, beispielsweise Ausgaben in HTML-Code einbetten.
Ein wesentlicher Paramter ist die immer vorhandene $site_id, aufgrund der der Content aus meiner MySQL-DB ausgelesen wird.
Zu dieser Aussage kann man keine sicherheitstechnische Antwort geben.
Lo!
Hi,
das beantwortet eigentlich schon meine Frage:
Gibt es ein Tool, dass "böse" Requests generiert und die auf die Site
abfeuert, oder muss ich mir nur jede Interaktion mit der MySQL-DB im
Einzelnen ansehen.
Deine Antwort ist eindeutig die zweite Alternative. Die Schwierigkeit,
die ich dabei sehe, ist mir vorzustellen, wie der Schadcode aussehen
könnte.
Daher versuche ich mal "genauere Aussagen zu machen":
Die Site wird beim Aufruf dynamisch aus dem im Parameter $site_id
übergebenen Wert aufgebaut. $site_id ist in Jeden Fall ein Integer.
In meiner MySQL-DB/Tabelle 'content_online' ist das Feld 'site_id'
der PrimaryKey. Der aus der Tabelle (Inner Joined mit anderen
Tabellen) zurückgegebene Datensatz enthält z.T. HTML und z.T.
PlainText der auf der Seite (immer von index.php) dann ausgegeben
wird.
Das ist natürlich nicht alles ...
Unterseiten können über /index/?site_id=1 oder mit /Request/Uri/
aufgerufen werden. Mod_Rewrite leitet die Anfrage immer nach
/index.php weiter. Ist der Paramter site_id beim Aufruf nicht mit
übergeben worden, wird in einer MySQL-DB/Tabelle 'structure' nach
'/Request/Uri/' gesucht, um die damit verknüpfte site_id zurückzugeben.
Bestimmten site_ids ein "dynamischer Container" zugeordnet. Das
heisst, dass der Content z.T. aus einem php-include-file kommt.
Wird. die Site bspw. mit site_id=145 aufgerufen, kommt include_145.inc.php
zur Ansicht. Das ist etwas komplexeres HTML und beinhaltet die
Suchmaske zum Einen und verarbeitet den Paramter $search_str nach
Abschicken dieses Formulars zum Anderen. $search_str wid wieder für
ein MySQL-Statement verwendet.
Wenn ich die Archillisferse einer, bzw. in meinem konkreten Fall dieser
Php/MySQL-Site also richtig verstehe, muss ich mir alle die Stellen
ansehen, in denen ich etwas aus $_GET (Kann man eine $_POST-Variable
eigentlich auch mit Schadcode belegen ausser über ein Eingabe-Feld?)
für ein SQL-Statement verwende, um SQL-Injection zu verhindern.
Sehe ich das richtig?
beste gruesse,
heinetz
Hi!
Gibt es ein Tool, dass "böse" Requests generiert und die auf die Site abfeuert, oder muss ich mir nur jede Interaktion mit der MySQL-DB im Einzelnen ansehen.
Es gibt keinen Request, der eindeutig als böse definiert werden kann. Es kommt immer auf die Umstände der jeweiligen Sicherheitslücke oder einer Kombination aus solchen an, was angestellt werden kann oder was nicht. Auch eine harmlos aussehende Abfrage kann ungewollt sein, weil man über sie sie vielleicht sensible Daten erhält, die man an anderer Stelle ebenfalls harmlos aussehend nutzen kann.
Deine Antwort ist eindeutig die zweite Alternative. Die Schwierigkeit, die ich dabei sehe, ist mir vorzustellen, wie der Schadcode aussehen könnte.
Der Schadcode ist im Prinzip irrelevant. Wichtig ist nur, dass alle als Daten und nicht als Code vorgesehenen Daten solche bleiben. Und das bleiben sie nur, wenn sie bei einem Einfügen in Code entsprechend der Notationsregeln für Stringliterale oder Zahlenliterale - oder was auch immer an dieser Stelle des Codes konkret benötigt wird - notiert werden. Schau mal in den Kontextwechsel-Artikel, Abschnitte 1 bis 4 sollten das Prinzip erläutern.
Die Site wird beim Aufruf dynamisch aus dem im Parameter $site_id übergebenen Wert aufgebaut. $site_id ist in Jeden Fall ein Integer.
Genauer gesagt: soll ein Integer sein. Alle bei einem Web-Request übergebenen Werte sind generell Strings. Integer und andere Typen werden sie nur bei entsprechender Behandlung (Typecast oder Parsen). (Kleine Ausnahme bilden speziell gestaltete Parameternamen, die unter PHP zur Bildung von Arrays führen.)
In meiner MySQL-DB/Tabelle 'content_online' ist das Feld 'site_id' der PrimaryKey. Der aus der Tabelle (Inner Joined mit anderen Tabellen) zurückgegebene Datensatz enthält z.T. HTML und z.T. PlainText der auf der Seite (immer von index.php) dann ausgegeben wird.
Das ist potentiell kritisch. Je nachdem, wie der HTML-Code zusammengestellt wurde, was mit ihm noch geschieht, bevor er zum Browser gelangt und welche Rolle dabei die anderen Daten spielen, muss genau betrachtet werden. Besonders unangenehm wird es, wenn Anwender selbst Code eingeben dürfen, der direkt in die Ausgabe gelangen oder gar von PHP evaluiert werden soll.
- Unterseiten können über /index/?site_id=1 oder mit /Request/Uri/ aufgerufen werden. Mod_Rewrite leitet die Anfrage immer nach /index.php weiter. Ist der Paramter site_id beim Aufruf nicht mit übergeben worden, wird in einer MySQL-DB/Tabelle 'structure' nach '/Request/Uri/' gesucht, um die damit verknüpfte site_id zurückzugeben.
Sehr allgemein beschrieben, da kann ich erstmal nichts weiter zu dem bereits von mir Gesagten hinzufügen.
- Bestimmten site_ids ein "dynamischer Container" zugeordnet. Das heisst, dass der Content z.T. aus einem php-include-file kommt. Wird. die Site bspw. mit site_id=145 aufgerufen, kommt include_145.inc.php zur Ansicht.
Hier muss sichergestellt sein, dass nichts anderes als die vorgesehenen Dateien ausgewählt werden können. Eine Prüfung gegen eine Liste mit genau definierten Werten wäre eine typische Lösung.
Das ist etwas komplexeres HTML und beinhaltet die Suchmaske zum Einen und verarbeitet den Paramter $search_str nach Abschicken dieses Formulars zum Anderen. $search_str wid wieder für ein MySQL-Statement verwendet.
Klingt nach dem üblichen Kontextwechseln, die einfach nur beachtet werden müssen.
Wenn ich die Archillisferse einer, bzw. in meinem konkreten Fall dieser Php/MySQL-Site also richtig verstehe, muss ich mir alle die Stellen ansehen, in denen ich etwas aus $_GET (Kann man eine $_POST-Variable eigentlich auch mit Schadcode belegen ausser über ein Eingabe-Feld?) für ein SQL-Statement verwende, um SQL-Injection zu verhindern.
Du musst nicht die Quelle betrachten, du musst immer das Ziel im Auge behalten. Egal wo die Daten herkommen, am Ziel muss alles syntaktisch einwandfrei eingefügt werden. Dazu musst du wissen, welche Zeichen im Ziel eine Sonderbedeutung haben und wie diese notiert werden müssen, damit sie diese Sonderbedeutung nicht haben und nur Datenbestandteil bleiben. Knifflig wird es, wenn mehrere Ziele ineinandergeschachtelt werden, beispielsweise Javascript und HTML.
Diese Zielbetrachtung kann man sich nur dann sparen, wenn die Daten aus verlässlicher Quelle kommen. Da muss aber sichergestellt sein, dass der gesamte Prozess vom Entstehen bis zum Zieleinfügen sicher ist. Das geht effizient und sicher nur bei sehr kurzen Verarbeitungswegen, beispielsweise ein String-Literal im PHP-Code stehend das in eine Ausgabe (SQL, HTML, wasauchimmer) eingefügt werden soll. Da kann man sehen: "Keine Sonderzeichen drin - keine Behandlung notwendig." Als Faustregel: Überall, wo man die einzufügenden Daten nicht direkt sehen kann, muss eine Behandlung erfolgen. Welche konkret nötig ist, ist fallabhängig.
Betrachte auch immer nur das nächstliegende Ziel. Um Ziele, die weiter entfernt liegen, muss sich der Code kümmern, der dort am nächsten dran ist. Sonst verliert sich leicht die Übersicht, was schon behandelt wurde und was nicht.
Lo!
Gibt es wirklich funktionierende Tools
oder Services, die man nutzen kann
Hi Heinetz,
ja, gibts. Brain 1.0 hat mir hier sehr gute Dienste geleistet. ;-)
Im Ernst, schreib Dir 2 Funktionen, die einmal den Input und einmal den Output Deiner Daten kontextgerecht behandeln. Danach hilft nur noch, die Scripte durchzukämmen und entsprechend Deiner Erwartung alle Variablen über Deine Funktionen mit entsprechenden Parametern umzuleiten.
Vergiss aber nicht, dass nicht aller Spökes über Deine Funktionen gedeckt werden können. Hierin kannst Du eigentlich nur die kontextgerechte Behandlung abdecken. Den Rest (z.B. Rechtevergaben einzelner Ein-/Ausgaben, usw.) musst Du zusätzlich manuell anlegen.
Viel Spaß und Erfolg, ich stand zuletzt (und ab dann immer wieder) vor derselben Aufgabe.
Jeromy