Einer der SQL-Injection-Angriffe, die in PHP völlig verboten sind
1. Arten von Injektionsangriffen
Es mag viele verschiedene Arten von Angriffsmotivationen geben, aber auf den ersten Blick scheint es so dass es mehr Typen gibt. Dies trifft sehr zu, wenn ein böswilliger Benutzer eine Methode erfindet, mit der mehrere Abfragen ausgeführt werden können. Wir werden dies später in diesem Artikel ausführlich besprechen.
Wenn Ihr Skript eine SELECT-Anweisung ausführt, kann ein Angreifer die Anzeige jeder Zeile in einer Tabelle erzwingen – indem er eine Bedingung wie „1=1“ in die WHERE-Klausel einfügt, wie unten gezeigt (die Injektionsteil ist fett dargestellt):
SELECT * FROM wines WHERE sorte = 'lagrein' OR 1=1;'
Wie wir Wie bereits erwähnt, kann dies an sich eine nützliche Information sein, da sie die allgemeine Struktur der Tabelle (etwas, was ein einfacher Datensatz nicht kann) sowie die Hinterhaltsanzeige mit Datensätzen vertraulicher Informationen offenlegt.
Ein aktualisierter Kommando-Hinterhalt stellt eine direktere Bedrohung dar. Durch Platzieren anderer Attribute in der SET-Klausel kann ein Angreifer jedes Feld im aktuell aktualisierten Datensatz ändern, wie zum Beispiel das folgende Beispiel (in dem der injizierte Teil fett dargestellt ist):
UPDATE wines SET type= 'red', 'vintage'='9999' WHERE sorte = 'lagrein'
Durch Einfügen einer Konstante wie 1=1 werden Bedingungen zum WHERE hinzugefügt Klausel einer Aktualisierungsanweisung. Dieser Korrekturbereich kann auf jeden Datensatz erweitert werden, wie zum Beispiel im folgenden Beispiel (in dem der Injektionsteil fett dargestellt ist):
UPDATE wines SET type= 'red', 'vintage '='9999 WHERE sorte = 'lagrein' OR 1=1;'
Die wahrscheinlich gefährlichste Anweisung ist DELETE – das ist nicht schwer vorstellbar. Die Injektionstechnik ähnelt dem, was wir bereits gesehen haben – durch Modifizieren der WHERE-Klausel, um den Umfang der betroffenen Datensätze zu erweitern, wie im folgenden Beispiel (in dem der Injektionsteil fett dargestellt ist):
DELETE FROM wines WHERE sorte = 'lagrein' OR 1=1;'
2. Multiple Query-Injection
Multiple Query-Injection erhöht das Potenzial Schaden, den ein Angreifer verursachen kann, indem er zulässt, dass mehrere schädliche Anweisungen in eine Abfrage einbezogen werden. Bei Verwendung der MySQL-Datenbank kann ein Angreifer dies leicht erreichen, indem er ein unerwartetes Abschlusszeichen in die Abfrage einfügt – ein injiziertes Anführungszeichen (einfaches oder doppeltes) markiert die erwartete Variable am Ende und fügt dann ein Semikolon hinzu. Jetzt kann am Ende des nun beendeten ursprünglichen Befehls ein zusätzlicher Angriffsbefehl hinzugefügt werden. Die ultimative schädliche Abfrage könnte so aussehen:
SELECT * FROM wines WHERE sorte = 'lagrein';
GRANT ALL ON *.* TO 'BadGuy@%' IDENTIFIED BY 'gotcha'; '
Durch diese Injektion wird ein neuer Benutzer „BadGuy“ erstellt und ihm Netzwerkprivilegien gewährt (alle Privilegien für alle Tabellen); darunter wird ein „unglückliches“ Passwort hinzugefügt diese einfache SELECT-Anweisung. Wenn Sie unserem Rat im vorherigen Artikel gefolgt sind, die Berechtigungen des Prozessbenutzers strikt einzuschränken, sollte dies nicht funktionieren, da der Webserver-Daemon nicht mehr über die von Ihnen entzogenen GRANT-Berechtigungen verfügt. Aber theoretisch könnte ein solcher Angriff BadGuy freie Hand geben, um die Kontrolle zu erlangen, die er über Ihre Datenbank hat.
Ob eine solche Mehrfachabfrage vom MySQL-Server verarbeitet wird, ist nicht eindeutig. Einiges davon kann auf unterschiedliche Versionen von MySQL zurückzuführen sein, meistens liegt es jedoch an der Art und Weise, wie mehrere Abfragen vorhanden sind. Das Überwachungsprogramm von MySQL lässt eine solche Abfrage vollständig zu. Die häufig verwendete MySQL-GUI-phpMyAdmin kopiert alle vorherigen Inhalte vor der endgültigen Abfrage und führt nur dies aus.
Allerdings werden die meisten Mehrfachabfragen in einem Injektionskontext von der MySQL-Erweiterung von PHP verarbeitet. Glücklicherweise ist die Ausführung mehrerer Anweisungen in einer Abfrage standardmäßig nicht zulässig; der Versuch, zwei Anweisungen auszuführen (wie die oben gezeigte Injektion), führt lediglich zu einem Fehler – es werden keine Fehler gesetzt und es werden keine Ausgabeinformationen angezeigt. In diesem Fall implementiert PHP zwar sein Standardverhalten nur „Schritt für Schritt“, schützt Sie jedoch vor den meisten einfachen Injektionsangriffen.
Die neue MySQLi-Erweiterung in PHP5 (siehe http://php.net/mysqli) unterstützt genau wie MySQL nicht von Natur aus mehrere Abfragen, bietet jedoch eine Funktion mysqli_multi_query(), die Sie bei der Implementierung unterstützt mehrere Abfragen - wenn Sie das wirklich wollen.
Allerdings ist die Situation noch schlimmer für SQLite, die einbettbare SQL-Datenbank-Engine, die mit PHP5 gebündelt ist (siehe http://sqlite.org/ und http://php.net/sqlite), die Aufmerksamkeit erregt aufgrund seiner einfachen Anwendung bei einer großen Anzahl von Benutzern beliebt. In einigen Fällen lässt SQLite solche Abfragen mit mehreren Anweisungen standardmäßig zu, da die Datenbank Batch-Abfragen optimieren kann, insbesondere die Batch-INSERT-Anweisungsverarbeitung, was sehr effizient ist. Wenn die Ergebnisse der Abfrage jedoch von Ihrem Skript verwendet werden (z. B. wenn Sie eine SELECT-Anweisung zum Abrufen von Datensätzen verwenden), lässt die Funktion sqlite_query() nicht die Ausführung mehrerer Abfragen zu.
3. INVISION Power BOARD SQL-Injection-Schwachstelle
Invision Power Board ist ein bekanntes Forensystem. Am 6. Mai 2005 wurde im Anmeldecode eine SQL-Injection-Sicherheitslücke entdeckt. Sein Erfinder ist James Bercegay von GulfTech Security Research.
Diese Anmeldeabfrage lautet wie folgt:
$DB->query('SELECT * FROM ibf_members WHERE id=$mid AND password='$pid'');
Wo , die Mitglieds-ID-Variable $mid und die Passwort-ID-Variable $pid werden von der Funktion my_cookie() mithilfe der folgenden zwei Codezeilen abgerufen:
$mid = intval($std->my_getcookie('member_id ')) ;
$pid = $std->my_getcookie('pass_hash');
Hier ruft die Funktion my_cookie() die angeforderten Variablen aus dem Cookie mithilfe der folgenden Anweisung ab:
return urldecode($ _COOKIE[$ibforums->vars['cookie_id'].$name]);
【Hinweis】Der von diesem Cookie zurückgegebene Wert wird grundsätzlich nicht verarbeitet. Obwohl $mid vor der Anwendung auf die Abfrage in eine Ganzzahl umgewandelt wird, bleibt $pid unverändert. Daher ist es anfällig für Injektionsangriffe, die wir zuvor besprochen haben.
Daher wird diese Schwachstelle durch die Behebung der Funktion my_cookie() wie folgt aufgedeckt:
if ( ! in_array( $name, array('topicsread', 'forum_read', 'collapseprefs ') ) )
{
return $this->
clean_value(urldecode($_COOKIE[$ibforums->vars['cookie_id'].$name])) ;
}
else
{
return urldecode($_COOKIE[$ibforums->vars['cookie_id'].$name]);
🎜>Nach einer solchen Korrektur werden die Schlüsselvariablen nach dem „Übergeben“ der globalen Funktion clean_value() zurückgegeben, während andere Variablen nicht überprüft werden.
Nachdem wir nun ein allgemeines Verständnis davon haben, was SQL-Injection ist, sein Injektionsprinzip und die Anfälligkeit dieser Injektion, wollen wir untersuchen, wie wir sie effektiv verhindern können. Glücklicherweise stellt uns PHP reichlich Ressourcen zur Verfügung, sodass wir mit voller Sicherheit vorhersagen können, dass eine Anwendung, die sorgfältig und gründlich mit unseren empfohlenen Techniken erstellt wurde, im Grunde jede Möglichkeit einer SQL-Injection aus Ihren Skripten ausschließt. Dies wird durch die „Liquidierung“ Ihrer Benutzer erreicht. Daten, bevor sie Schaden anrichten können.
4. Definieren Sie jeden Wert in Ihrer Abfrage
Wir empfehlen Ihnen, sicherzustellen, dass Sie jeden Wert in Ihrer Abfrage definieren. Als erstes sind String-Werte betroffen, ebenso wie Inhalte, bei denen man normalerweise die Verwendung von „einfachen“ (statt „doppelten“) Anführungszeichen erwarten würde. Einerseits kann die Verwendung von doppelten Anführungszeichen, um PHP den Austausch von Variablen innerhalb eines Strings zu ermöglichen, die Eingabe von Abfragen erleichtern, andererseits wird dies (zugegebenermaßen nur ein sehr geringer Teil) auch den Bedarf an zukünftigem PHP verringern Code-Analyse-Arbeit.
Als nächstes verwenden wir die Nicht-Injektionsabfrage, die wir zu Beginn verwendet haben, um dieses Problem zu veranschaulichen:
SELECT * FROM wines WHERE sorte = 'lagrein'
Oder in PHP-Anweisung ausgedrückt als:
$query = 'SELECT * FROM wines WHERE sorte = '$variety'';
Technisch gesehen müssen Anführungszeichen nicht auf numerische Werte angewendet werden. Wenn es Ihnen jedoch nichts ausmacht, einen Wert für ein Feld wie Wein in Anführungszeichen zu setzen, und wenn Ihr Benutzer einen Nullwert in Ihr Formular eingibt, sehen Sie etwa Folgendes: Abfrage:
SELECT * FROM wines WHERE vintage =
Natürlich ist diese Abfrage syntaktisch ungültig; die folgende Syntax ist jedoch gültig:
SELECT * FROM wines WHERE vintage = ''
Die zweite Abfrage wird (wahrscheinlich) zurückgeben Nichts, aber es wird zumindest keine Fehlermeldung zurückgegeben.
Aus der vorherigen Diskussion können wir bisher den wichtigen Ursprung der SQL-Injection erkennen kommt oft zu einem unerwarteten Formularimport. Wenn Sie dem Benutzer jedoch die Möglichkeit geben, bestimmte Werte über ein Formular zu übermitteln, sollten Sie eine gute Vorstellung davon haben, welche Eingaben Sie erhalten möchten – dies kann es einfacher machen, die Gültigkeit der Eingaben des Benutzers zu überprüfen. Wir haben solche Verifizierungsheader bereits in früheren Artikeln besprochen, daher fassen wir hier nur kurz die wichtigsten Punkte zusammen, die wir damals besprochen haben. Wenn Sie eine Zahl betrachten, können Sie eine dieser Techniken verwenden, um sicherzustellen, dass Sie tatsächlich einen numerischen Typ erhalten:
Verwenden Sie die Funktion is_int() (oder is_integer() oder is_long()). .
· Wenden Sie die Funktion gettype() an.
· Wenden Sie die Funktion intval() an.
· Wenden Sie die Funktion settype() an.
Um die Länge der Benutzereingabe zu überprüfen, können Sie die Funktion strlen() verwenden. Um zu überprüfen, ob eine gewünschte Uhrzeit oder ein gewünschtes Datum gültig ist, können Sie die Funktion strtotime() verwenden. Dadurch wird mit ziemlicher Sicherheit sichergestellt, dass der Import eines Benutzers kein Semikolon enthält (es sei denn, Satzzeichen können zulässigerweise enthalten sein). Sie können dies ganz einfach mit Hilfe der Funktion strpos() erreichen, wie unten gezeigt:
if( strpos( $variety, ';' ) ) exit ( '$variety ist ein ungültiger Wert für Vielfalt !' );
Wie wir bereits erwähnt haben, sollten Sie das Vorhandensein vieler Probleme leicht erkennen können, solange Sie die Erwartungen Ihrer Benutzereingaben sorgfältig analysieren.
6. Filtern Sie jedes verdächtige Zeichen aus Ihrer Abfrage heraus
Obwohl wir in früheren Artikeln besprochen haben, wie man Titel mit gefährlichen Zeichen herausfiltert, wollen wir diesen Titel hier kurz übertreiben und zusammenfassen Nochmals:
· Verwenden Sie nicht den Befehl magic_quotes_gpc oder seine Funktion „Behind-the-Scenes-Partner“-addslashes(), die in der Anwendungsentwicklung eingeschränkt ist. Und diese Funktion erfordert auch die Anwendung eines zusätzlichen Schritts – die Anwendung der Funktion „stripslashes()“.
· Im Vergleich dazu wird die Funktion mysql_real_escape_string() häufiger verwendet, weist aber auch ihre eigenen Mängel auf.