it-swarm.com.de

Welche Seiten sind für SQL-Injection anfällig?

Ich glaube, ich verstehe die Grundlagen der SQL-Injection. Ich weiß auch, dass die Verwendung vorbereiteter Anweisungen mit PHP-Dateien der beste Weg ist, um eine SQL-Injection zu verhindern. Mir wurde immer gesagt, dass SQL-Injection am häufigsten auftritt, wenn ein Angreifer gültige SQL-Befehle in Formulardatenfelder oder -dateien eingibt Eingabefelder auf einer öffentlich zugänglichen Site.

Wenn ich jedoch PHP -Dateien auf meiner Site habe, auf die nur ein authentifizierter Benutzer zugreifen kann, ist es dann immer noch zu 100% erforderlich, vorbereitete Anweisungen zu verwenden?

Was ist mit SQL-Abfragen, für deren Ausführung keine externen Benutzerdaten erforderlich sind?

Etwas wie:

SELECT * FROM tableName

Wenn ich keine Variablen an eine Abfrage übergebe, ist sie dann immer noch anfällig für SQL-Injection?

12
Austin

Vertrauen Sie allen authentifizierten Benutzern vollständig? Einschließlich, dass ihre Konten nicht von Angreifern kompromittiert werden? Es ist schlecht, wenn ein Angreifer Zugriff auf ein Konto erhält, aber weitaus schlimmer, wenn er dies nutzen kann, um den Rest Ihrer Datenbank zu stehlen.

Für Ihren zweiten Punkt wäre das von Ihnen verwendete Beispiel nicht anfällig. Seien Sie jedoch vorsichtig mit mehr Grenzfällen wie

$query = "SELECT * FROM tableName WHERE secret='".dbquery("SELECT secret FROM otherTable WHERE id=3")."'";

Wenn es möglich wäre, eine Nutzlast in otherTable in der Spalte secret für den Datensatz mit id 3 einzufügen, wäre dies anfällig für SQLi zweiter Ordnung , auch wenn die Einfügeroutine vorbereitete Anweisungen verwendet hat.

Laut Kommentar:

SELECT * FROM tableName WHERE secret=(SELECT secret FROM otherTable WHERE id=3)

wird in SQL ausgeführt, also kein Problem. Das Problem tritt auf, wenn Daten aus der Datenbank auf der Anwendungsebene als vertrauenswürdig betrachtet und in späteren Abfragen verwendet werden.

46
Matthew

Sie sagen: "Ich glaube, ich verstehe die Grundlagen der SQL-Injection." aber der Rest der Frage impliziert, dass Sie vielleicht noch etwas Verwirrung haben. In jedem Fall ist dies ein wichtiges Thema, und viele Menschen sind weiterhin verwirrt über das Problem und die Lösung.

Ich weiß auch, dass die Verwendung vorbereiteter Anweisungen mit PHP -Dateien der beste Weg ist, um SQL-Injection zu verhindern.

Die Verwendung vorbereiteter Anweisungen ist eine notwendige, aber nicht ausreichende Bedingung, um vor SQL Injection (SQLi) zu schützen. Um zu verstehen, warum, ist es wichtig, die Ursache von SQL Injection-Schwachstellen zu verstehen. Hier sind die Ursachen:

  1. Verketten von SQL-Anweisungen aus Benutzer-/Client-Eingaben.

Das ist es. Wenn Sie Eingaben vom Benutzer in eine SQL-Anweisung einfügen, die Sie dann in der Datenbank kompilieren, sind Sie möglicherweise SQLi-Schwachstellen ausgesetzt (und sind dies wahrscheinlich auch). Wenn Sie dies tun und eine vorbereitete Anweisung verwenden, haben Sie nichts gelöst. Sie sind immer noch verwundbar.

Warum werden vorbereitete Aussagen immer als Antwort gegeben? Wenn wir das SQL nicht mit der Eingabe verketten können, bedeutet dies, dass unser SQL mehr oder weniger fest codiert sein muss. Aber was ist, wenn Sie die Benutzerinformationen für denjenigen zurückziehen möchten, der sich gerade angemeldet hat? Wir können nicht jedes Mal eine neue SQL-Anweisung schreiben, wenn wir einen neuen Benutzer haben.

Vorbereitete Aussagen

Was vorbereitete Anweisungen zur Beseitigung dieses Problems nützlich macht, ist, dass sie Parameter berücksichtigen. Das heißt, anstatt so etwas zu tun:

// Don't do this!  Subject to injection
"SELECT credit_card_number FROM user_data where userid = '" + userinput + "'"

Wir können das schaffen:

"SELECT credit_card_number FROM user_data where userid = ?"

Und kompilieren Sie diese Anweisung in der Datenbank. Wenn wir es ausführen, müssen wir einen Parameterwert übergeben, sonst schlägt die Abfrage fehl. Warum löst dies das Problem? Angenommen, ein Angreifer findet heraus, wie er an die Zeichenfolge gelangt: foo' OR 1 = 1 OR 'a' = 'a in den Benutzereingabewert. Im ersten Fall wird das folgende SQL ausgeführt:

SELECT credit_card_number FROM user_data where userid = 'foo' OR 1 = 1 OR 'a' = 'a';

Rückgabe jeder Zeile in der Tabelle. Im zweiten Fall wird diese SQL ausgeführt:

SELECT credit_card_number FROM user_data where userid = ?

mit dem Parameter foo' OR 1 = 1 OR 'a' = 'a. Es sei denn, Sie haben einen Benutzer mit der unwahrscheinlichen ID foo' OR 1 = 1 OR 'a' = 'a Es werden keine Ergebnisse angezeigt. Aber lassen Sie uns klar sein, Sie können den ersten (falschen) Ansatz mit vorbereiteten Aussagen verwenden und Sie werden immer noch verwundbar sein. Die vorbereitete Aussage enthält nichts Magisches, das die Eingabe bereinigt. Es ist so, dass Sie den zweiten (richtigen) Ansatz nicht mit einer regulären Anweisung verwenden können, die keine Parameter unterstützt.

Ich denke, dass Leute, die dies verstehen, oft die Kurzform "vorbereitete Anweisungen verwenden" verwenden, weil der Hauptgrund für ihre Verwendung darin besteht, dass sie Parameter unterstützen. Aber es sind wirklich die Parameter, die die Lösung für dieses Problem sind.

27
JimmyJames

Zusätzlich zu Matthews großartiger Antwort sind Sie möglicherweise auch dann anfällig für CSRF , wenn Sie Ihren Benutzern vertrauen. Dies könnte es einem Angreifer ermöglichen, eine SQL-Injection durchzuführen, ohne dies zu tun ein Konto.

Ein Angreifer kann möglicherweise einen Link oder ein Formular erstellen, auf das ein authentifizierter Benutzer versehentlich klicken oder senden kann, wodurch eine SQL-Injection erfolgt. Aus diesem Grund versichere ich, dass Sie Benutzereingaben niemals vertrauen sollten und dass Sie parametrisierte Abfragen für alle Benutzereingaben bereinigen und verwenden sollten.

5
Kodos Johnson

Dies ist eine sehr beliebte Frage zu Stack Overflow, und deshalb habe ich eine Art "Standardantwort" darauf entwickelt.

1. Warum versuchst du zu verhandeln?

Zunächst einmal klingt die Frage so, als würden Sie versuchen, sich einen "Rabatt" in der Entwicklung auszuhandeln. Aber warum versuchst du es so? Warum stellt sich jemals eine solche Frage? Sind vorbereitete Aussagen für Sie zu schwer zu erfassen/umzusetzen? Dann sollten Sie eine andere Frage stellen: "Wie mache ich vorbereitete Aussagen weniger langweilig?" Tatsächlich ist eine vorbereitete Anweisung einfacher als jede andere Methode der Datenbankinteraktion.

Es gibt also überhaupt keinen Grund für eine solche Frage.

2. SQL-Injection ist nur ein Nebeneffekt.

Sie müssen Ihre Abfragen unabhängig von möglichen Bedrohungen formatieren. Sie tun es nicht für die berühmten Bobby Tables , sondern für ein bescheidenes Mädchen, Sarah O'Hara (oder einen anderen Menschen oder eine andere Entität, die zufällig einen Namen trägt, der eine Datenbank erstellen könnte Drossel, wenn nicht richtig formatiert).

Es handelt sich also nicht um eine SQL-Injection, für die Sie vorbereitete Anweisungen verwenden müssen, sondern lediglich, um sicherzustellen, dass Ihre Abfrage immer syntaktisch korrekt ist.

3. Bei der manuellen Formatierung gibt es zu viele mögliche Fallstricke

Wenn Sie keine vorbereiteten Anweisungen verwenden, sind Sie damit abgefunden, Ihre Daten manuell zu formatieren, und auf diesem Weg gibt es viele Fallstricke. Ich habe mich bemüht, sie in meinem einem Artikel über SQL-Injection zusammenzufassen. Hier ist ein Auszug:

  1. Die manuelle Formatierung kann unvollständig sein. Nehmen wir den Fall der Bobby-Tabellen. Es ist ein perfektes Beispiel für unvollständige Formatierung: Eine Zeichenfolge, die wir der Abfrage hinzugefügt haben, wurde nur in Anführungszeichen gesetzt, aber nicht maskiert! Wie wir gerade aus dem oben Gesagten gelernt haben, sollten Zitieren und Escaping immer zusammenpassen (zusammen mit der Einstellung der richtigen Codierung für die Escape-Funktion). In einer üblichen PHP Anwendung, die die SQL-Zeichenfolgenformatierung separat ausführt (teilweise in der Abfrage und teilweise an einer anderen Stelle), ist es sehr wahrscheinlich, dass ein Teil der Formatierung einfach übersehen wird.

  2. Die manuelle Formatierung kann auf das falsche Literal angewendet werden. Keine große Sache, solange wir vollständige Formatierung verwenden verwenden (da dies einen sofortigen Fehler verursacht, der in der Entwicklungsphase behoben werden kann), aber in Kombination mit unvollständiger Formatierung ist dies eine echte Katastrophe. Auf der großartigen Website von Stack Overflow gibt es Hunderte von Antworten, die vorschlagen , Bezeichner genauso wie Zeichenfolgen zu umgehen. Das wäre völlig nutzlos und würde eine SQL-Injection verursachen.

  3. Die manuelle Formatierung ist im Wesentlichen eine nicht obligatorische Maßnahme . Erstens gibt es einen offensichtlichen Mangel an Aufmerksamkeit, bei dem die richtige Formatierung einfach vergessen werden kann. Aber es gibt einen wirklich seltsamen Fall - viele PHP Benutzer lehnen häufig absichtlich die Anwendung von Formatierungen ab, da sie die Daten bis heute immer noch in "sauber" und "sauber" trennen. unreine "," Benutzereingaben "und" Nichtbenutzereingaben "usw. Ich denke, dass" sichere "Daten keine Formatierung benötigen. Was ein einfacher Unsinn ist - erinnern Sie sich an Sarah O'Hara. Aus Sicht der Formatierung ist das Ziel wichtig. Ein Entwickler muss sich um den Typ des SQL-Literal kümmern, nicht um die Datenquelle. Geht eine Zeichenfolge zur Abfrage? Es muss dann als String formatiert werden. Egal, ob es sich um Benutzereingaben handelt oder nur auf mysteriöse Weise aus dem Nichts inmitten der Codeausführung aufgetaucht ist.

  4. Die manuelle Formatierung kann durch einen beträchtlichen Abstand von der eigentlichen Abfrageausführung getrennt werden.

Das am meisten unterschätzte und übersehene Problem. Das Wichtigste von allen ist jedoch, dass es alle anderen Regeln allein verderben kann, wenn es nicht befolgt wird.

Fast jeder PHP Benutzer ist versucht, die gesamte "Desinfektion" an einem einzigen Ort durchzuführen, weit entfernt von der eigentlichen Abfrageausführung, und ein derartiger falscher Ansatz ist allein eine Quelle unzähliger Fehler:

  • erstens kann man, da keine Abfrage vorliegt, nicht sagen, welche Art von SQL-Literal dies für ein bestimmtes Stück darstellt - und daher haben wir beide Formatierungsregeln (1) und (2) gleichzeitig verletzt.
  • wir haben mehr als einen Ort für die Desinfektion (es kann sich entweder um eine zentralisierte Einrichtung oder um eine direkte Formatierung handeln) und fordern eine Katastrophe, da ein Entwickler denken würde, dass dies von einem anderen getan wurde oder bereits woanders gemacht wurde usw.
  • da wir mehr als einen Ort für die Bereinigung haben, besteht die Gefahr, dass Daten doppelt bereinigt werden (z. B. ein Entwickler hat sie am Einstiegspunkt formatiert und ein anderer - vor der Ausführung der Abfrage). Dies ist nicht gefährlich, lässt die Website jedoch äußerst unprofessionell aussehen
  • durch vorzeitige Formatierung wird die Quellvariable beschädigt und für andere Zwecke unbrauchbar.

    1. Schließlich nimmt die manuelle Formatierung immer zusätzlichen Platz im Code ein, wodurch er sich verwickelt und aufgebläht.

4. Eine vorbereitete Aussage ist keine Silberkugel.

Zu guter Letzt. Wir alle müssen uns daran erinnern, dass Datenliterale nicht die einzigen variablen Teile in der Abfrage sind. Manchmal muss auch ein Bezeichner oder ein Schlüsselwort hinzugefügt werden. Vorbereitete Anweisungen helfen in diesem Fall nicht weiter, dennoch sollten solche Abfrageteile insgesamt nicht weniger geschützt sein. Glücklicherweise ist die Liste der möglichen Varianten für Bezeichner und Schlüsselwörter immer begrenzt, sodass wir den Ansatz Whitelisting verwenden können, den ich in meine Antwort auf die Referenzfrage zum Stapelüberlauf) beschrieben habe , also werde ich mich nicht wiederholen.


Um Ihre letzte Frage zu beantworten: Nein, eine Abfrage ohne variable Teile ist nicht anfällig, da es keinen Sinn macht, sie einzufügen.

2

Es gibt keinen wirklich vertrauenswürdigen Benutzer. Selbst wenn Sie Insider-Bedrohungen ignorieren (was heutzutage ein eklatantes Versehen ist), gibt es andere Risiken. Der Benutzer hat möglicherweise sein Kennwort auf ein Post-It geschrieben, oder sein Gerät ist möglicherweise mit Malware kompromittiert, die Ihre Sicherheitsanfälligkeiten ausnutzen kann, ohne dass der Benutzer dies weiß.

Indem Sie eine SQL-Injection-Lücke für any user offen lassen, gewähren Sie ihnen effektiv uneingeschränkten, nicht überwachten Zugriff auf Ihre Datenbank. Je nachdem, wie gut Sie Ihr Sicherheitsmodell eingerichtet haben, können sie wahrscheinlich auch alles löschen.

Grundsätzlich müssen Sie entscheiden, gegen wen Sie sich schützen, und Ihre Anstrengungen darauf aufbauen. Ein offenes SQL-Injection-Loch zu lassen, ist jedoch nur schlampig und setzt Sie dem Risiko aus, keinen greifbaren Nutzen zu erzielen. Wenn Sie parametrisierte Abfragen korrekt implementieren, sollte es keinen Unterschied in der Anstrengung geben, es richtig zu machen.

Eine letzte Überlegung ... Sicherheit ist keine binäre Sache. Sie sollten viele Ebenen haben, die jeweils vor unterschiedlichen Angriffsvektoren schützen. Wenn eine Ebene gefährdet ist, schützen die verbleibenden Ebenen Ihre Daten (oder verringern den Verlust). In diesem Szenario können Angreifer bei einem Cross-Site-Anforderungsfälschungsangriff Ihre Datenbank besitzen. Wenn Sie die SQL-Injection gepatcht haben, ist das Schlimmste, was sie tun können, was Ihre App einem Benutzer unter normalen Bedingungen ermöglicht ¹.

¹ (Und um dies zu mildern, können Sie eine Ratenbegrenzung oder ein Überwachungs-/Warnsystem implementieren. Sie können für immer weitermachen.).

0
Basic