Die Idee ist sehr einfach: Die Abfrage und die Daten werden separat an den Datenbankserver gesendet .
Das ist alles.
Die Wurzel des SQL-Injection-Problems liegt in der Mischung von Code und Daten.
Tatsächlich ist unsere SQL-Abfrage ein legitimes Programm . Und wir erstellen ein solches Programm dynamisch und fügen einige Daten im laufenden Betrieb hinzu. Daher können die Daten den Programmcode stören und sogar ändern, wie jedes SQL-Injection-Beispiel zeigt (alle Beispiele in PHP / MySQL):
$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";
erzeugt eine regelmäßige Abfrage
SELECT * FROM users where id=1
während dieser Code
$spoiled_data = "1; DROP TABLE users;"
$query = "SELECT * FROM users where id=$spoiled_data";
erzeugt eine böswillige Sequenz
SELECT * FROM users where id=1; DROP TABLE users;
Dies funktioniert, weil wir die Daten direkt zum Programmkörper hinzufügen und sie Teil des Programms werden, sodass die Daten das Programm ändern können. Abhängig von den übergebenen Daten wird entweder eine reguläre Ausgabe oder eine Tabelle users
gelöscht.
Während wir bei vorbereiteten Anweisungen unser Programm nicht ändern, bleibt es intakt.
Das ist der Punkt.
Wir senden zuerst ein Programm an den Server
$db->prepare("SELECT * FROM users where id=?");
Dabei werden die Daten durch eine Variable ersetzt, die als Parameter oder Platzhalter bezeichnet wird.
Beachten Sie, dass genau dieselbe Abfrage ohne Daten an den Server gesendet wird! Und dann senden wir die Daten mit der zweiten Anforderung, die im Wesentlichen von der Abfrage selbst getrennt ist:
$db->execute($data);
Es kann also unser Programm nicht ändern und keinen Schaden anrichten.
Ganz einfach - nicht wahr?
Das einzige, was ich hinzufügen muss, das in jedem Handbuch immer weggelassen wurde:
Vorbereitete Anweisungen können nur Datenliterale schützen , können jedoch nicht mit anderen Abfrageteilen verwendet werden.
Wenn wir also beispielsweise einen dynamischen Bezeichner hinzufügen müssen - beispielsweise einen Feldnamen -, können uns vorbereitete Anweisungen nicht weiterhelfen. Ich habe die Angelegenheit kürzlich erklärt , damit ich mich nicht wiederhole.
$spoiled_data = "1; DROP TABLE users;"
->$query = "SELECT * FROM users where id=$spoiled_data";
im Vergleich zu:$db->prepare("SELECT * FROM users where id=?");
->$data = "1; DROP TABLE users;"
->$db->execute($data);
. Werden sie nicht dasselbe tun?Hier ist SQL zum Einrichten eines Beispiels:
Die Inject-Klasse ist anfällig für SQL-Injection. Die Abfrage wird dynamisch zusammen mit Benutzereingaben eingefügt. Die Abfrage sollte Informationen über Bob anzeigen. Entweder Gehalt oder Bonus, basierend auf Benutzereingaben. Der böswillige Benutzer manipuliert jedoch die Eingabe, die die Abfrage beschädigt, indem er das Äquivalent eines 'oder true' zur where-Klausel anheftet, sodass alles zurückgegeben wird, einschließlich der Informationen über Aaron, die ausgeblendet werden sollten.
Wenn Sie dies ausführen, ist der erste Fall bei normaler Verwendung und der zweite bei böswilliger Injektion:
Sie sollten Ihre SQL-Anweisungen nicht mit einer Zeichenfolgenverkettung von Benutzereingaben erstellen. Es ist nicht nur anfällig für Injection, sondern hat auch Auswirkungen auf das Caching auf dem Server (die Anweisung ändert sich, sodass es weniger wahrscheinlich ist, dass ein SQL-Anweisungscache getroffen wird, während im Bindungsbeispiel immer dieselbe Anweisung ausgeführt wird).
Hier ist ein Beispiel für die Bindung, um diese Art der Injektion zu vermeiden:
Wenn Sie dies mit derselben Eingabe wie im vorherigen Beispiel ausführen, funktioniert der Schadcode nicht, da kein Zahlungstyp vorhanden ist, der dieser Zeichenfolge entspricht:
quelle
PREPARE
Erstellt eine feste benannte Anweisung, die bereits analysiert wurde (dh die Anweisung wird sich unabhängig von der Eingabe nicht mehr ändern), währendEXECUTE
die benannte Anweisung ausgeführt wird, die die Parameter bindet. Da esPREPARE
nur eine Sitzungsdauer hat, sieht es wirklich so aus, als ob es aus Leistungsgründen gedacht ist, nicht um die Injektion über psql-Skripte zu verhindern. Für den psql-Zugriff können Berechtigungen für gespeicherte Prozeduren erteilt und die Parameter in den Prozessen gebunden werden.Grundsätzlich werden bei vorbereiteten Anweisungen die von einem potenziellen Hacker eingehenden Daten als Daten behandelt - und es gibt keine Möglichkeit, sie mit Ihrer Anwendungs-SQL zu vermischen und / oder als SQL zu interpretieren (was passieren kann, wenn übergebene Daten direkt in Ihre Daten eingegeben werden) Anwendung SQL).
Dies liegt daran, dass vorbereitete Anweisungen die SQL-Abfrage zuerst "vorbereiten", um einen effizienten Abfrageplan zu finden, und die tatsächlichen Werte senden, die vermutlich später aus einem Formular eingehen - zu diesem Zeitpunkt wird die Abfrage tatsächlich ausgeführt.
Weitere tolle Infos hier:
Vorbereitete Anweisungen und SQL Injection
quelle
Ich las die Antworten durch und hatte immer noch das Bedürfnis, den entscheidenden Punkt hervorzuheben, der die Essenz vorbereiteter Aussagen beleuchtet. Betrachten Sie zwei Möglichkeiten, um Ihre Datenbank abzufragen, wenn Benutzereingaben betroffen sind:
Naiver Ansatz
Man verkettet Benutzereingaben mit einer partiellen SQL-Zeichenfolge, um eine SQL-Anweisung zu generieren. In diesem Fall kann der Benutzer schädliche SQL-Befehle einbetten, die dann zur Ausführung an die Datenbank gesendet werden.
Zum Beispiel können böswillige Benutzereingaben dazu führen,
SQLString
dass sie gleich sind"SELECT * FROM CUSTOMERS WHERE NAME='James';DROP TABLE CUSTOMERS;'
SQLString
Enthält aufgrund des böswilligen Benutzers 2 Anweisungen, wobei die 2. ("DROP TABLE CUSTOMERS"
) Schaden anrichtet.Vorbereitete Aussagen
In diesem Fall wird die Benutzereingabe aufgrund der Trennung von Abfrage und Daten niemals als SQL-Anweisung behandelt und daher niemals ausgeführt . Aus diesem Grund würde jeder injizierte schädliche SQL-Code keinen Schaden anrichten. Das
"DROP TABLE CUSTOMERS"
würde also im obigen Fall niemals ausgeführt werden.Kurz gesagt, mit vorbereiteten Anweisungen wird bösartiger Code, der über Benutzereingaben eingeführt wird, nicht ausgeführt!
quelle
Wenn Sie eine vorbereitete Anweisung erstellen und an das DBMS senden, wird sie als SQL-Abfrage zur Ausführung gespeichert.
Sie binden Ihre Daten später so an die Abfrage, dass das DBMS diese Daten als Abfrageparameter für die Ausführung (Parametrisierung) verwendet. Das DBMS verwendet die von Ihnen gebundenen Daten nicht als Ergänzung zur bereits kompilierten SQL-Abfrage. Es sind einfach die Daten.
Dies bedeutet, dass es grundsätzlich unmöglich ist, eine SQL-Injection mit vorbereiteten Anweisungen durchzuführen. Die Art der vorbereiteten Anweisungen und ihre Beziehung zum DBMS verhindert dies.
quelle
In SQL Server ist die Verwendung einer vorbereiteten Anweisung definitiv injektionssicher, da die Eingabeparameter keine Abfrage bilden. Dies bedeutet, dass die ausgeführte Abfrage keine dynamische Abfrage ist. Beispiel für eine anfällige SQL-Injection-Anweisung.
Wenn der Wert in der Variablen inoutusername so etwas wie a 'oder 1 = 1 - ist, lautet diese Abfrage jetzt:
Und der Rest wird danach kommentiert
--
, sodass er niemals ausgeführt und umgangen wird, wenn das vorbereitete Anweisungsbeispiel wie folgt verwendet wird.Tatsächlich können Sie also keinen weiteren Parameter einsenden, um eine SQL-Injection zu vermeiden ...
quelle
Der Schlüsselbegriff lautet
need not be correctly escaped
. Das bedeutet, dass Sie sich keine Sorgen machen müssen, wenn Leute versuchen, Bindestriche, Apostrophe, Zitate usw. einzufügen.Es wird alles für Sie erledigt.
quelle
Nehmen wir an, Sie haben das in einem Servlet, das Sie richtig haben. Wenn eine böswillige Person einen schlechten Wert für "Filter" übergeben hat, können Sie Ihre Datenbank hacken.
quelle
Grundursache Nr. 1 - Das Trennzeichenproblem
SQL-Injection ist möglich, weil wir Anführungszeichen verwenden, um Zeichenfolgen abzugrenzen und auch Teile von Zeichenfolgen zu sein, was es manchmal unmöglich macht, sie zu interpretieren. Wenn wir Trennzeichen hätten, die nicht in Zeichenfolgendaten verwendet werden könnten, wäre eine SQL-Injection niemals aufgetreten. Durch das Lösen des Trennzeichenproblems wird das SQL-Injection-Problem beseitigt. Strukturabfragen machen das.
Grundursache Nr. 2 - Menschliche Natur, Menschen sind schlau und einige schlaue Menschen sind bösartig und alle Menschen machen Fehler
Die andere Grundursache für die SQL-Injektion ist die menschliche Natur. Menschen, einschließlich Programmierer, machen Fehler. Wenn Sie bei einer strukturierten Abfrage einen Fehler machen, ist Ihr System nicht anfällig für SQL-Injection. Wenn Sie keine strukturierten Abfragen verwenden, können Fehler zu einer Sicherheitsanfälligkeit bezüglich SQL-Injection führen.
Wie strukturierte Abfragen die Hauptursachen von SQL Injection beheben
Strukturierte Abfragen Lösen Sie das Trennzeichenproblem, indem Sie SQL-Befehle in eine Anweisung und die Daten in eine separate Programmieranweisung einfügen. Programmieranweisungen erzeugen die erforderliche Trennung.
Strukturierte Abfragen verhindern, dass durch menschliches Versagen kritische Sicherheitslücken entstehen. In Bezug auf Menschen, die Fehler machen, kann eine SQL-Injektion nicht erfolgen, wenn Strukturabfragen verwendet werden. Es gibt Möglichkeiten, die SQL-Injection zu verhindern, bei denen keine strukturierten Abfragen erforderlich sind. Ein normaler menschlicher Fehler bei diesen Ansätzen führt jedoch normalerweise zu einer zumindest gewissen Exposition gegenüber der SQL-Injection. Strukturierte Abfragen sind vor SQL-Injection ausfallsicher. Sie können fast alle Fehler der Welt mit strukturierten Abfragen machen, wie bei jeder anderen Programmierung, aber keine, die Sie machen können, kann in ein System umgewandelt werden, das von SQL Injection übernommen wird. Deshalb sagen die Leute gerne, dass dies der richtige Weg ist, um eine SQL-Injektion zu verhindern.
Da haben Sie es also, die Ursachen der SQL-Injektion und die naturstrukturierten Abfragen, die sie unmöglich machen, wenn sie verwendet werden.
quelle