wake-up-neo.com

Wie vermeidet oder verhindert ein PreparedStatement die SQL-Injection?

Ich weiß, dass PreparedStatements SQL Injection vermeiden/verhindern. Wie macht es das? Handelt es sich bei der endgültigen Formularabfrage, die mit PreparedStatements erstellt wurde, um eine Zeichenfolge oder eine andere?

107
Prabhu R

Das Problem bei der SQL-Injection ist, dass eine Benutzereingabe als Teil der SQL-Anweisung verwendet wird. Mit vorbereiteten Anweisungen können Sie erzwingen, dass die Benutzereingabe als Inhalt eines Parameters (und nicht als Teil des SQL-Befehls) behandelt wird.

Wenn Sie die Benutzereingabe jedoch nicht als Parameter für Ihre vorbereitete Anweisung verwenden, sondern stattdessen Ihren SQL-Befehl durch Zusammenfügen von Zeichenfolgen erstellen, sind Sie immer noch anfällig für SQL-Injektionen, auch wenn Sie vorbereitete Anweisungen verwenden.

66
tangens

Betrachten Sie zwei Möglichkeiten, dasselbe zu tun:

PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();

Oder

PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();

Wenn "Benutzer" von Benutzereingabe kam und die Benutzereingabe war

Robert'); DROP TABLE students; --

Dann würden Sie in erster Linie abgespritzt werden. In der zweiten Phase wären Sie in Sicherheit und Little Bobby Tables wäre für Ihre Schule registriert.

181
Paul Tomblin

Um zu verstehen, wie PreparedStatement SQL Injection verhindert, müssen wir die Phasen der Ausführung von SQL-Abfragen verstehen.

1. Kompilierungsphase. 2. Ausführungsphase.

Immer wenn die SQL Server-Engine eine Abfrage empfängt, muss sie die folgenden Phasen durchlaufen:

Query Execution Phases

  1. Analyse- und Normalisierungsphase: In dieser Phase wird die Abfrage auf Syntax und Semantik überprüft. Es wird geprüft, ob in der Abfrage verwendete Referenztabellen und -spalten vorhanden sind oder nicht. Es hat auch viele andere Aufgaben zu erledigen, aber lassen Sie uns nicht ins Detail gehen.

  2. Kompilierungsphase: In dieser Phase werden Stichwörter, die in Abfragen wie select, from, etc verwendet werden, in ein für den Computer verständliches Format konvertiert. Dies ist die Phase, in der die Abfrage interpretiert und die entsprechenden Maßnahmen festgelegt werden. Es hat auch viele andere Aufgaben zu erledigen, aber lassen Sie uns nicht ins Detail gehen.

  3. Plan zur Abfrageoptimierung: In dieser Phase wird der Entscheidungsbaum erstellt, um herauszufinden, wie die Abfrage ausgeführt werden kann. Es wird die Anzahl der Ausführungsarten von Abfragen und die mit den einzelnen Ausführungsarten von Abfragen verbundenen Kosten ermittelt. Es wird der beste Plan zum Ausführen einer Abfrage ausgewählt.

  4. Cache: Der beste Plan, der im Plan zur Abfrageoptimierung ausgewählt wurde, wird im Cache gespeichert, sodass er bei der nächsten Abfrage nicht weitergeleitet werden muss Wieder Phase 1, Phase 2 und Phase 3. Wenn die nächste Abfrage eingeht, wird sie direkt im Cache überprüft und von dort abgeholt, um ausgeführt zu werden.

  5. Ausführungsphase: In dieser Phase wird die angegebene Abfrage ausgeführt und die Daten werden als ResultSet -Objekt an den Benutzer zurückgegeben.

Verhalten der PreparedStatement-API in den obigen Schritten

  1. PreparedStatements sind keine vollständigen SQL-Abfragen und enthalten Platzhalter, die zur Laufzeit durch vom Benutzer bereitgestellte Daten ersetzt werden.

  2. Immer wenn ein PreparedStatment mit Platzhaltern an das SQL Server-Modul übergeben wird, durchläuft es die folgenden Phasen

    1. Analyse- und Normalisierungsphase
    2. Kompilierungsphase
    3. Plan zur Abfrageoptimierung
    4. Cache (Kompilierte Abfragen mit Platzhaltern werden im Cache gespeichert.)

UPDATE user set username =? und Passwort =? WO id =?

  1. Die obige Abfrage wird analysiert, mit Platzhaltern als Sonderbehandlung kompiliert, optimiert und zwischengespeichert. Die Abfrage ist zu diesem Zeitpunkt bereits kompiliert und in ein maschinenverständliches Format konvertiert. Wir können also sagen, dass die im Cache gespeicherte Abfrage vorkompiliert ist und nur Platzhalter durch vom Benutzer bereitgestellte Daten ersetzt werden müssen.

  2. Zur Laufzeit, wenn vom Benutzer bereitgestellte Daten eingehen, wird die vorkompilierte Abfrage aus dem Cache abgerufen und die Platzhalter werden durch vom Benutzer bereitgestellte Daten ersetzt.

PrepareStatementWorking

(Denken Sie daran, dass nach dem Ersetzen von Platzhaltern durch Benutzerdaten die endgültige Abfrage nicht erneut kompiliert/interpretiert wird und das SQL Server-Modul Benutzerdaten als reine Daten behandelt und kein SQL, das analysiert oder kompiliert werden muss wieder, das ist das Schöne an PreparedStatement.)

Wenn die Abfrage die Kompilierungsphase nicht erneut durchlaufen muss, werden alle auf den Platzhaltern ersetzten Daten als reine Daten behandelt und haben für das SQL Server-Modul keine Bedeutung. Die Abfrage wird direkt ausgeführt.

Hinweis: Es ist die Kompilierungsphase nach der Analysephase, die die Abfragestruktur versteht/interpretiert und ihr ein aussagekräftiges Verhalten verleiht. Im Fall von PreparedStatement wird die Abfrage nur einmal kompiliert und die zwischengespeicherte kompilierte Abfrage wird ständig abgerufen, um Benutzerdaten zu ersetzen und auszuführen.

Aufgrund der einmaligen Kompilierungsfunktion von PreparedStatement ist es frei von SQL Injection-Angriffen.

Eine ausführliche Erklärung mit einem Beispiel erhalten Sie hier: http://javabypatel.blogspot.in/2015/09/how-prepared-statement-inJava-prevents-sql-injection.html

96
Jayesh

Die in einem PreparedStatement verwendete SQL wird im Treiber vorkompiliert. Ab diesem Zeitpunkt werden die Parameter als Literalwerte und nicht als ausführbare Teile von SQL an den Treiber gesendet. Daher kann kein SQL über einen Parameter injiziert werden. Ein weiterer positiver Nebeneffekt von PreparedStatements (Vorkompilierung + Senden nur von Parametern) ist eine verbesserte Leistung, wenn die Anweisung mehrmals ausgeführt wird, auch wenn für die Parameter unterschiedliche Werte verwendet werden (vorausgesetzt, der Treiber unterstützt PreparedStatements), da der Treiber nicht jedes Mal eine SQL-Analyse und -Kompilierung durchführen muss Zeit ändern sich die Parameter.

26
Travis Heseman

Die vorbereitete Aussage ist sicherer. Es wird ein Parameter in den angegebenen Typ konvertiert.

Zum Beispiel konvertiert stmt.setString(1, user); den Parameter user in einen String.

Angenommen, der Parameter enthält eine SQL-Zeichenfolge mit einem ausführbaren Befehl: Die Verwendung einer vorbereiteten Anweisung lässt dies nicht zu.

Dazu wird ein Metazeichen (eine automatische Konvertierung) hinzugefügt.

Dies macht es sicherer.

3
Guru R Handa

Ich rate es wird eine Zeichenfolge sein. Die Eingabeparameter werden jedoch an die Datenbank gesendet und die entsprechenden Darstellungen/Konvertierungen werden vor dem Erstellen einer tatsächlichen SQL-Anweisung angewendet.

Um Ihnen ein Beispiel zu geben, könnte es versuchen zu sehen, ob CAST/Conversion funktioniert.
Wenn es funktioniert, könnte es daraus eine endgültige Aussage machen.

   SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))

Probieren Sie ein Beispiel mit einer SQL-Anweisung aus, die einen numerischen Parameter akzeptiert.
Übergeben Sie nun eine Zeichenfolgenvariable (mit einem numerischen Inhalt, der als numerischer Parameter zulässig ist). Löst es einen Fehler aus?

Übergeben Sie nun eine Zeichenfolgenvariable (mit Inhalten, die als numerischer Parameter nicht zulässig sind). Schau was passiert?

3
shahkalpesh

SQL-Injection: Wenn der Benutzer die Möglichkeit hat, etwas einzugeben, das Teil der SQL-Anweisung sein könnte

Beispielsweise:

String query = "INSERT INTO students VALUES ('' + user + '')"

bei Benutzereingabe "Robert"); DROP TABLE Studenten; - ”als Eingabe bewirkt es eine SQL-Injection

Wie vorbereitete Aussage verhindert das?

String query = "INSERT INTO students VALUES (" + ": name" + "") "

parameters.addValue ("Name", Benutzer);

=> bei erneuter Benutzereingabe "Robert"); DROP TABLE Studenten; - “wird die Eingabezeichenfolge im Treiber als Literalwerte vorkompiliert und kann wie folgt umgewandelt werden:

CAST („Robert“); DROP TABLE Studenten; - „AS varchar (30))

Am Ende wird die Zeichenfolge buchstäblich als Name in die Tabelle eingefügt.

http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/

2
jack

Wie in dieser Beitrag erklärt, hilft das PreparedStatement alleine nicht, wenn Sie immer noch Strings verketten.

Zum Beispiel kann ein Angreifer immer noch Folgendes tun:

  • rufen Sie eine Sleep-Funktion auf, damit alle Datenbankverbindungen ausgelastet sind und Ihre Anwendung nicht verfügbar ist
  • sensible Daten aus der DB extrahieren
  • mgehen der Benutzerauthentifizierung

Nicht nur SQL, sondern auch JPQL oder HQL können gefährdet werden, wenn Sie keine Bindungsparameter verwenden.

Unterm Strich sollten Sie beim Erstellen von SQL-Anweisungen niemals die Verkettung von Zeichenfolgen verwenden. Verwenden Sie zu diesem Zweck eine dedizierte API:

1
Vlad Mihalcea

PreparedStatement:

1) Vorkompilierung und DB-seitiges Caching der SQL-Anweisung führen zu einer insgesamt schnelleren Ausführung und der Möglichkeit, dieselbe SQL-Anweisung in Stapeln wiederzuverwenden.

2) Automatische Verhinderung von SQL-Injection-Angriffen durch integriertes Ausblenden von Anführungszeichen und anderen Sonderzeichen. Beachten Sie, dass Sie dazu eine der PreparedStatement-Methoden setXxx () verwenden müssen, um den Wert festzulegen.

1
Mukesh Kumar