Ich weiß, dass PreparedStatements SQL Injection vermeiden / verhindern. Wie macht es das? Wird die endgültige Formularabfrage, die mit PreparedStatements erstellt wird, eine Zeichenfolge oder eine andere sein?
Ich weiß, dass PreparedStatements SQL Injection vermeiden / verhindern. Wie macht es das? Wird die endgültige Formularabfrage, die mit PreparedStatements erstellt wird, eine Zeichenfolge oder eine andere sein?
Antworten:
Das Problem bei der SQL-Injection besteht darin, dass eine Benutzereingabe als Teil der SQL-Anweisung verwendet wird. Mithilfe vorbereiteter Anweisungen können Sie erzwingen, dass die Benutzereingaben als Inhalt eines Parameters (und nicht als Teil des SQL-Befehls) behandelt werden.
Wenn Sie jedoch die Benutzereingabe nicht als Parameter für Ihre vorbereitete Anweisung verwenden, sondern stattdessen Ihren SQL-Befehl durch Zusammenfügen von Zeichenfolgen erstellen, sind Sie auch bei Verwendung vorbereiteter Anweisungen für SQL-Injektionen anfällig .
Betrachten Sie zwei Möglichkeiten, um 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 der Benutzereingabe kam und die Benutzereingabe war
Robert'); DROP TABLE students; --
Dann würden Sie in erster Linie abgespritzt. Im zweiten Fall wären Sie in Sicherheit und Little Bobby Tables würden für Ihre Schule registriert.
Um zu verstehen, wie PreparedStatement SQL Injection verhindert, müssen wir die Phasen der Ausführung von SQL Query verstehen.
1. Kompilierungsphase. 2. Ausführungsphase.
Immer wenn die SQL Server-Engine eine Abfrage empfängt, muss sie die folgenden Phasen durchlaufen:
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 gehen wir nicht ins Detail.
Kompilierungsphase: In dieser Phase werden in Abfragen verwendete Schlüsselwörter wie select, from, where usw. in ein maschinenverständliches Format konvertiert. Dies ist die Phase, in der die Abfrage interpretiert und die entsprechenden auszuführenden Maßnahmen festgelegt werden. Es hat auch viele andere Aufgaben zu erledigen, aber gehen wir nicht ins Detail.
Abfrageoptimierungsplan: In dieser Phase wird ein Entscheidungsbaum erstellt, um herauszufinden, wie Abfragen ausgeführt werden können. Es werden die Anzahl der Möglichkeiten zur Ausführung der Abfrage und die mit jeder Art der Ausführung der Abfrage verbundenen Kosten ermittelt. Es wird der beste Plan für die Ausführung einer Abfrage ausgewählt.
Cache: Der beste im Abfrageoptimierungsplan ausgewählte Plan wird im Cache gespeichert, sodass er beim nächsten Eingehen derselben Abfrage nicht erneut Phase 1, Phase 2 und Phase 3 durchlaufen muss. Wenn die nächste Abfrage eingeht, wird sie direkt im Cache überprüft und von dort zur Ausführung abgeholt.
Ausführungsphase:
In dieser Phase wird die angegebene Abfrage ausgeführt und die Daten werden als ResultSet
Objekt an den Benutzer zurückgegeben .
PreparedStatements sind keine vollständigen SQL-Abfragen und enthalten Platzhalter, die zur Laufzeit durch tatsächlich vom Benutzer bereitgestellte Daten ersetzt werden.
Immer wenn ein PreparedStatment mit Platzhaltern an die SQL Server-Engine übergeben wird, durchläuft es die folgenden Phasen
UPDATE Benutzer set username =? und Passwort =? WO id =?
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.
Zur Laufzeit, wenn vom Benutzer bereitgestellte Daten eingehen, wird die vorkompilierte Abfrage aus dem Cache abgerufen und die Platzhalter durch vom Benutzer bereitgestellte Daten ersetzt.
(Denken Sie daran, dass nach dem Ersetzen von Platzhaltern durch Benutzerdaten die endgültige Abfrage nicht erneut kompiliert / interpretiert wird und die SQL Server-Engine Benutzerdaten als reine Daten behandelt und nicht als SQL, das erneut analysiert oder kompiliert werden muss. Das ist das Schöne an PreparedStatement. )
Wenn die Abfrage nicht erneut kompiliert werden muss, werden alle auf den Platzhaltern ersetzten Daten als reine Daten behandelt und haben für die SQL Server-Engine keine Bedeutung. Sie führt die Abfrage direkt aus.
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 erfasst, 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 Beispiel finden Sie hier: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
Die in einem PreparedStatement verwendete SQL wird auf dem 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 mithilfe eines Parameters injiziert werden. Ein weiterer vorteilhafter Nebeneffekt von PreparedStatements (Vorkompilierung + nur Parameter senden) ist eine verbesserte Leistung, wenn die Anweisung auch mit unterschiedlichen Werten für die Parameter mehrmals ausgeführt wird (vorausgesetzt, der Treiber unterstützt PreparedStatements), da der Treiber nicht jeweils SQL-Analyse und -Kompilierung durchführen muss Mal ändern sich die Parameter.
Ich denke, es wird eine Saite sein. Die Eingabeparameter werden jedoch an die Datenbank gesendet und die entsprechenden Umwandlungen / Konvertierungen werden angewendet, bevor eine tatsächliche SQL-Anweisung erstellt wird.
Um Ihnen ein Beispiel zu geben, wird möglicherweise versucht, festzustellen, ob CAST / Conversion funktioniert.
Wenn es funktioniert, könnte es eine endgültige Aussage daraus erstellen.
SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))
Versuchen Sie ein Beispiel mit einer SQL-Anweisung, die einen numerischen Parameter akzeptiert.
Versuchen Sie nun, eine Zeichenfolgenvariable zu übergeben (mit einem numerischen Inhalt, der als numerischer Parameter akzeptabel ist). Löst es einen Fehler aus?
Versuchen Sie nun, eine Zeichenfolgenvariable zu übergeben (deren Inhalt als numerischer Parameter nicht akzeptabel ist). Schau was passiert?
Die vorbereitete Anweisung ist sicherer. Es wird ein Parameter in den angegebenen Typ konvertiert.
Beispielsweise stmt.setString(1, user);
wird der user
Parameter in einen String konvertiert .
Angenommen, der Parameter enthält eine SQL-Zeichenfolge, die einen ausführbaren Befehl enthält : Die Verwendung einer vorbereiteten Anweisung lässt dies nicht zu.
Es fügt Metazeichen (auch bekannt als automatische Konvertierung) hinzu.
Dies macht es sicherer.
SQL-Injection: Wenn der Benutzer die Möglichkeit hat, etwas einzugeben, das Teil der SQL-Anweisung sein könnte
Beispielsweise:
String query = "INSERT INTO student VALUES ('" + user + "')"
bei Benutzereingabe „Robert“); DROP TABLE Studenten; - ”als Eingabe verursacht es eine SQL-Injection
Wie eine vorbereitete Aussage verhindert dies?
String query = "INSERT INTO student VALUES ('" + ": name" + "')"
parameters.addValue ("Name", Benutzer);
=> wenn der Benutzer erneut "Robert" eingibt); DROP TABLE Studenten; - “, die Eingabezeichenfolge wird auf dem Treiber als Literalwerte vorkompiliert, und ich denke, sie 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/
CAST(‘Robert’);
von CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
brechen, dann würde er die Tabelle fallen lassen, wenn dies der Fall wäre. Es stoppt die Injektion, daher glaube ich, dass das Beispiel einfach nicht vollständig genug ist, um das Szenario zu erklären.
PreparedStatement:
1) Die Vorkompilierung und das DB-seitige Caching der SQL-Anweisung führt 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 Entkommen von Anführungszeichen und anderen Sonderzeichen. Beachten Sie, dass Sie hierfür eine der PreparedStatement setXxx () -Methoden verwenden müssen, um den Wert festzulegen.
Wie in diesem Beitrag erläutert , PreparedStatement
hilft Ihnen das allein nicht, wenn Sie noch Strings verketten.
Zum Beispiel kann ein betrügerischer Angreifer immer noch Folgendes tun:
Nicht nur SQL, sondern auch JPQL oder HQL können kompromittiert 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:
In Vorbereitete Anweisungen muss der Benutzer Daten als Parameter eingeben. Wenn der Benutzer einige anfällige Anweisungen wie DROP TABLE oder SELECT * FROM USERS eingibt, sind die Daten nicht betroffen, da diese als Parameter der SQL-Anweisung betrachtet werden