security prevent - Wie funktioniert die SQL-Injection aus dem XKCD-Comic "Bobby Tables"?




cheat sheet (11)

Einfach zu sehen:

(Quelle: https://xkcd.com/327/ )

Was macht diese SQL?

Robert'); DROP TABLE STUDENTS; --

Ich weiß sowohl ' als auch" -- sind für Kommentare, aber wird das Wort DROP nicht kommentiert, da es Teil derselben Zeile ist?


Answers

In diesem Fall ist 'kein Kommentarzeichen. Es wird zum Abgrenzen von Zeichenfolgenliteralen verwendet. Der Comic-Zeichner setzt auf die Idee, dass die betreffende Schule irgendwo einen dynamischen Sql hat, der ungefähr so ​​aussieht:

$sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";

Jetzt beendet das Zeichen das String-Literal, bevor der Programmierer es erwartet hat. Kombiniert mit dem; Zeichen, um die Anweisung zu beenden, kann ein Angreifer jetzt jede beliebige SQL hinzufügen. Der - Kommentar am Ende soll sicherstellen, dass jegliche verbleibende sql in der ursprünglichen Anweisung nicht verhindert, dass die Abfrage auf dem Server kompiliert wird.

FWIW, ich denke auch, dass der fragliche Comic ein wichtiges Detail falsch hat: Wenn du darüber nachdenkst, deine Datenbankeingaben zu bereinigen, wie es der Comic vorschlägt, machst du es immer noch falsch. Stattdessen sollten Sie in Betracht ziehen, Ihre Datenbankeingaben in Quarantäne zu stellen , und der richtige Weg dazu besteht in parametrisierten Abfragen.


Nein, ' ist kein Kommentar in SQL, sondern ein Trennzeichen.

Mama hat vermutet, dass der Datenbankprogrammierer eine Anfrage gestellt hat, die wie folgt aussieht:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');

(Zum Beispiel) um den neuen Studenten hinzuzufügen, wobei der $xxx Variableninhalt direkt aus einem HTML-Formular entnommen wurde, ohne das Format zu überprüfen oder Sonderzeichen zu umgehen.

Also wenn $firstName Robert'); DROP TABLE students; -- enthält Robert'); DROP TABLE students; -- Robert'); DROP TABLE students; -- Robert'); DROP TABLE students; -- Das Datenbankprogramm führt die folgende Anfrage direkt in der DB aus:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');

dh. Es wird die Insert-Anweisung vorzeitig beenden, den vom Cracker gewünschten bösartigen Code ausführen und dann den Rest des Codes auskommentieren.

Mmm, ich bin zu langsam, ich sehe schon 8 Antworten vor mir in der orangenen Band ... :-) Ein beliebtes Thema, so scheint es.


So funktioniert es: Nehmen wir an, der Administrator sucht nach Studentenakten

Robert'); DROP TABLE STUDENTS; --

Da das Administratorkonto über hohe Berechtigungen verfügt, ist das Löschen der Tabelle aus diesem Konto möglich.

Der Code zum Abrufen des Benutzernamens von der Anfrage ist

Jetzt wäre die Abfrage in etwa so (um die Schüler-Tabelle zu durchsuchen)

String query="Select * from student where username='"+student_name+"'";

statement.executeQuery(query); //Rest of the code follows

Die resultierende Abfrage wird

Select * from student where username='Robert'); DROP TABLE STUDENTS; --

Da die Benutzereingabe nicht bereinigt ist, wurde die obige Abfrage in 2 Teile manipuliert

Select * from student where username='Robert'); 

DROP TABLE STUDENTS; --

Der Doppelstrich (-) wird nur den verbleibenden Teil der Abfrage auskommentieren.

Dies ist gefährlich, da es die Kennwortauthentifizierung aufheben kann, falls vorhanden

Der erste wird die normale Suche durchführen.

Der zweite Schüler wird den Tischschüler fallen lassen, wenn der Account ausreichende Privilegien hat (im Allgemeinen wird der Schuladministrator eine solche Anfrage ausführen und die oben erwähnten Privilegien haben).


Sagen Sie, Sie hätten naiv eine Methode zur Erstellung eines Schülers geschrieben:

void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}

Und jemand gibt den Namen Robert'); DROP TABLE STUDENTS; -- Robert'); DROP TABLE STUDENTS; --

Was auf der Datenbank ausgeführt wird, ist diese Abfrage:

INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')

Das Semikolon beendet den Einfügebefehl und startet einen anderen; das - kommentiert den Rest der Linie. Der Befehl DROP TABLE wird ausgeführt ...

Deshalb sind Bindeparameter eine gute Sache.


Das '); beendet die Abfrage, es startet keinen Kommentar. Dann löscht es die Schüler-Tabelle und kommentiert den Rest der Abfrage, die ausgeführt werden sollte.


Nehmen wir an, der Name wurde in einer Variablen namens $Name . Sie führen dann diese Abfrage aus:

INSERT INTO Students VALUES ( '$Name' )

Was Sie bekommen, ist:

INSERT INTO Students VALUES ( 'Robert' );  DROP TABLE STUDENTS; --' )

Das -- kommentiert nur den Rest der Zeile.


TL; DR

-- The application accepts input, in this case 'Nancy', without attempting to
-- sanitize the input, such as by escaping special characters
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1

-- SQL injection occurs when input into a database command is manipulated to
-- cause the database server to execute arbitrary SQL
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE

-- The student records are now gone - it could have been even worse!
school=> SELECT * FROM students;
ERROR:  relation "students" does not exist
LINE 1: SELECT * FROM students;
                      ^

Dies lässt den Schülertisch fallen. Um zu verdeutlichen, was gerade passiert, versuchen wir es mit einer einfachen Tabelle, die nur das Namensfeld enthält und fügen Sie eine einzelne Zeile hinzu (getestet mit PostgreSQL 9.1.2):

school=> CREATE TABLE students (name TEXT PRIMARY KEY);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "students_pkey" for table "students"
CREATE TABLE
school=> INSERT INTO students VALUES ('John');
INSERT 0 1

Nehmen wir an, die Anwendung verwendet die folgende SQL, um Daten in die Tabelle einzufügen:

INSERT INTO students VALUES ('foobar');

Ersetzen Sie foobar durch den tatsächlichen Namen des Schülers. Eine normale Einfügeoperation würde folgendermaßen aussehen:

--                            Input:   Nancy
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1

Wenn wir die Tabelle abfragen, bekommen wir folgendes:

school=> SELECT * FROM students;
 name
-------
 John
 Nancy
(2 rows)

Was passiert, wenn wir den Namen von Little Bobby Tables in die Tabelle einfügen?

--                            Input:   Robert'); DROP TABLE students; --
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE

Die SQL-Injektion hier ist das Ergebnis des Namens des Studenten, der die Anweisung beendet und einen separaten DROP TABLE Befehl enthält; Die zwei Bindestriche am Ende der Eingabe sollen jeden übrig gebliebenen Code auskommentieren, der sonst einen Fehler verursachen würde. Die letzte Zeile der Ausgabe bestätigt, dass der Datenbankserver die Tabelle gelöscht hat.

Es ist wichtig zu beachten, dass die Anwendung während der INSERT Operation die Eingabe nicht auf Sonderzeichen prüft und daher beliebige Eingaben in den SQL-Befehl eingeben kann. Dies bedeutet, dass ein böswilliger Benutzer in ein Feld, das normalerweise für Benutzereingaben vorgesehen ist, spezielle Symbole wie Anführungszeichen zusammen mit beliebigem SQL-Code einfügen kann, damit das Datenbanksystem es ausführt, daher SQL "injection" .

Das Ergebnis?

school=> SELECT * FROM students;
ERROR:  relation "students" does not exist
LINE 1: SELECT * FROM students;
                      ^

SQL Injection ist die Datenbank, die einer Sicherheitslücke in einem Betriebssystem oder einer Anwendung entspricht. Die möglichen Auswirkungen eines erfolgreichen SQL-Injection-Angriffs sind nicht zu unterschätzen. Je nach Konfiguration des Datenbanksystems und der Anwendung kann der Angreifer Datenverluste verursachen (wie in diesem Fall), unberechtigten Zugriff auf Daten erlangen oder sogar ausführen beliebiger Code auf dem Host-Rechner selbst.

Wie im XKCD-Comic erwähnt, besteht eine Möglichkeit zum Schutz vor SQL-Injection-Angriffen darin, Datenbankeingaben zu bereinigen, z. B. durch das Leeren von Sonderzeichen, sodass sie den zugrunde liegenden SQL-Befehl nicht ändern können und daher keinen beliebigen SQL-Code ausführen können. Wenn Sie parametrisierte Abfragen verwenden, z. B. mithilfe von SqlParameter in ADO.NET, wird die Eingabe automatisch für Sie SqlParameter .


Es lässt den Schülertisch fallen.

Der ursprüngliche Code im Schulprogramm sieht wahrscheinlich ungefähr so ​​aus

q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";

Dies ist der naive Weg, um Text in eine Abfrage einzufügen, und ist sehr schlecht , wie Sie sehen werden.

Nach den Werten aus dem Vornamen, zweiter Vorname Textfeld FNMName.Text (das ist Robert'); DROP TABLE STUDENTS; -- Robert'); DROP TABLE STUDENTS; -- Robert'); DROP TABLE STUDENTS; -- ) und das Nachname-Textfeld LName.Text (nennen wir es Derper ) werden mit dem Rest der Abfrage verkettet, das Ergebnis sind nun eigentlich zwei Abfragen, die durch das Statement-Terminator (Semikolon) getrennt sind. Die zweite Abfrage wurde in die erste Abfrage eingefügt . Wenn der Code diese Abfrage für die Datenbank ausführt, sieht das so aus

INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')

was in einfachem Englisch grob zu den zwei Abfragen übersetzt:

Fügen Sie der Tabelle "Students" einen neuen Datensatz mit dem Namen "Robert" hinzu.

und

Löschen Sie die Students-Tabelle

Alles nach der zweiten Abfrage ist als Kommentar markiert : --', 'Derper')

Das ' im Namen des Schülers ist kein Kommentar, es ist der abschließende String-Begrenzer . Da der Name des Schülers ein String ist, wird er syntaktisch benötigt, um die hypothetische Anfrage zu vervollständigen. Injektionsangriffe funktionieren nur, wenn die SQL-Abfrage, die sie injizieren, zu gültigem SQL führt .

dan04 dem scharfsinnigen Kommentar von dan04 nochmals dan04


Der Verfasser der Datenbank hat wahrscheinlich ein

sql = "SELECT * FROM STUDENTS WHERE (STUDENT_NAME = '" + student_name + "') AND other stuff";
execute(sql);

Wenn student_name der angegebene ist, wird die Auswahl mit dem Namen "Robert" ausgeführt und die Tabelle wird gelöscht. Der Teil "-" ändert den Rest der angegebenen Abfrage in einen Kommentar.


Ein einfaches Anführungszeichen ist der Anfang und das Ende eines Strings. Ein Semikolon ist das Ende einer Anweisung. Also wenn sie eine Auswahl wie diese machen würden:

Select *
From Students
Where (Name = '<NameGetsInsertedHere>')

Die SQL würde werden:

Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
--             ^-------------------------------^

Auf einigen Systemen würde die select zuerst ausgeführt, gefolgt von der Anweisung drop ! Die Nachricht lautet: VERBINDEN SIE WERTE NICHT IN IHR SQL. Verwenden Sie stattdessen Parameter!






security validation sql-injection