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


Einfach zu sehen:

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

Was macht diese SQL?

Robert'); DROP TABLE STUDENTS; --

Ich kenne beide ' und -- sind für Kommentare, aber nicht das Wort DROP auch kommentiert, da es Teil derselben Zeile ist?


984
2017-12-01 21:50


Ursprung


Antworten:


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 die naive Art, Text in eine Abfrage einzufügen sehr schlecht, wie du sehen wirst.

Nach den Werten aus dem Vornamen, zweiter Vorname Textfeld FNMName.Text (welches ist Robert'); DROP TABLE STUDENTS; --) und das Textfeld für den Nachnamen LName.Text (Nennen wir es Derper) sind mit dem Rest der Abfrage verkettet, das Ergebnis ist jetzt tatsächlich zwei Abfragen getrennt durch die Anweisungsabschlusszeichen (Semikolon). Die zweite Abfrage wurde durchgeführt injiziert in die erste. 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 Studenten ist kein Kommentar, es ist das Schließen Zeichenfolgenbegrenzer. 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.

Bearbeitet nochmal nach dan04ist kluger Kommentar


1018
2017-12-01 21:55



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

INSERT INTO Students VALUES ( '$Name' )

Der Code platziert fälschlicherweise alles, was der Benutzer als Variable bereitgestellt hat. Sie wollten, dass das SQL:

INSERT IN Studenten WERTE ('Robert Tische`)

Aber ein cleverer Benutzer kann liefern, was er will:

INSERT IN Studenten WERTE ('Robert'); DROP TABLE Studenten; -')

Was Sie bekommen, ist:

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

Das -- nur kommentiert den Rest der Zeile.


546
2017-09-14 10:12



Wie schon alle anderen darauf hingewiesen haben, die '); schließt die ursprüngliche Aussage und dann folgt eine zweite Aussage. Die meisten Frameworks, einschließlich Sprachen wie PHP, haben inzwischen Standard-Sicherheitseinstellungen, die nicht mehrere Anweisungen in einer SQL-Zeichenfolge zulassen. In PHP können Sie beispielsweise mehrere Anweisungen in einer einzigen SQL-Zeichenfolge ausführen, indem Sie die Option verwenden mysqli_multi_query Funktion.

Sie können jedoch eine vorhandene SQL-Anweisung über SQL-Injection bearbeiten, ohne eine zweite Anweisung hinzufügen zu müssen. Nehmen wir an, Sie haben ein Login-System, das einen Benutzernamen und ein Passwort mit dieser einfachen Auswahl überprüft:

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);

Wenn Sie zur Verfügung stellen peter als Benutzername und secret Als Passwort würde die resultierende SQL-Zeichenfolge wie folgt aussehen:

SELECT * FROM users WHERE username='peter' and (password='secret')

Alles ist gut. Stellen Sie sich vor, Sie geben diese Zeichenfolge als Passwort an:

' OR '1'='1

Dann wäre die resultierende SQL-Zeichenfolge wie folgt:

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')

Damit können Sie sich bei jedem Konto anmelden, ohne das Passwort zu kennen. Sie müssen also nicht in der Lage sein, zwei Anweisungen zu verwenden, um SQL-Injection zu verwenden, obwohl Sie mehr destruktive Dinge tun können, wenn Sie mehrere Anweisungen liefern können.


145
2017-12-01 22:01



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 Schüler hinzuzufügen, wo der $xxx Variable Inhalte wurden direkt aus einem HTML-Formular übernommen, ohne das Format zu überprüfen oder Sonderzeichen zu umgehen.

Also, wenn $firstName enthält Robert'); DROP TABLE students; -- Das Datenbankprogramm führt die folgende Anfrage direkt in der Datenbank 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.


68
2017-09-26 20:20



TL; DR

- Die Anwendung akzeptiert Eingaben, in diesem Fall "Nancy", ohne zu versuchen
- Bereinigen Sie die Eingabe, indem Sie z. B. Sonderzeichen umgehen
Schule => EINSCHALTEN IN WERTE ('Nancy');
EINFÜGEN 0 1

- Die SQL-Injektion erfolgt, wenn die Eingabe in einen Datenbankbefehl manipuliert wird
- Veranlassen, dass der Datenbankserver beliebiges SQL ausführt
Schule => INSERT IN Studenten Werte ('Robert'); DROP TABLE Studenten; - ');
EINFÜGEN 0 1
Abfalltabelle

- Die Schülerunterlagen sind jetzt weg - es hätte noch schlimmer kommen können!
Schule => SELECT * FROM Studenten;
FEHLER: Beziehung "Studenten" existiert nicht
Zeile 1: SELECT * FROM Studenten;
                      ^

Dies löscht (löscht) die Schüler-Tabelle.

(Alle Codebeispiele in dieser Antwort wurden auf einem PostgreSQL 9.1.2-Datenbankserver ausgeführt.)

Um es deutlich zu machen, was gerade passiert, versuchen wir es mit einer einfachen Tabelle, die nur das Namensfeld enthält und fügen Sie eine einzelne Zeile hinzu:

school => CREATE TABLE Schüler (Name TEXT PRIMARY KEY);
HINWEIS: CREATE TABLE / PRIMARY KEY erstellt den impliziten Index "students_pkey" für die Tabelle "students".
TABELLE ERSTELLEN
Schule => INSERT IN Studenten Werte ('John');
EINFÜGEN 0 1

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

INSERT IN Studenten WERTE ('Foobar');

Ersetzen foobar mit dem tatsächlichen Namen des Studenten. Eine normale Einfügeoperation würde folgendermaßen aussehen:

- Eingabe: Nancy
Schule => EINSCHALTEN IN WERTE ('Nancy');
EINFÜGEN 0 1

Wenn wir die Tabelle abfragen, bekommen wir folgendes:

Schule => SELECT * FROM Studenten;
 Name
-------
 John
 Nancy
(2 Reihen)

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

- Eingabe: Robert '); DROP TABLE Studenten; -
Schule => INSERT IN Studenten Werte ('Robert'); DROP TABLE Studenten; - ');
EINFÜGEN 0 1
Abfalltabelle

Die SQL-Injection hier ist das Ergebnis des Namens des Studenten, der die Anweisung beendet und ein separates einfügt DROP TABLEBefehl; 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 bemerken, dass während der INSERT Operation Die Anwendung überprüft die Eingabe nicht auf Sonderzeichen und erlaubt daher die Eingabe beliebiger Eingaben in den SQL-Befehl. Dies bedeutet, dass ein böswilliger Benutzer in ein Feld, das normalerweise für Benutzereingaben gedacht ist, spezielle Symbole wie Anführungszeichen zusammen mit beliebigem SQL-Code einfügen kann, damit das Datenbanksystem es ausführt SQLInjektion.

Das Ergebnis?

Schule => SELECT * FROM Studenten;
FEHLER: Beziehung "Studenten" existiert nicht
Zeile 1: SELECT * FROM Studenten;
                      ^

SQL-Injection ist das Datenbankäquivalent zu einem Remote willkürliche Codeausführung Sicherheitslücke in einem Betriebssystem oder einer Anwendung. 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 SqlParameter In ADO.NET wird die Eingabe mindestens automatisch bereinigt, um die SQL-Injektion zu verhindern.

Die Bereinigung von Eingaben auf Anwendungsebene kann jedoch komplexere SQL-Injektionstechniken nicht verhindern. Beispielsweise, es gibt Möglichkeiten, die zu umgehen mysql_real_escape_string PHP-Funktion. Für zusätzlichen Schutz werden viele Datenbanksysteme unterstützt vorbereitete Aussagen. Bei richtiger Implementierung im Backend können vorbereitete Anweisungen die SQL-Injektion unmöglich machen, indem Dateneingaben semantisch vom Rest des Befehls getrennt behandelt werden.


33
2017-12-01 21:56



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 ein 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; die - kommentiert den Rest der Linie. Der Befehl DROP TABLE wird ausgeführt ...

Deshalb sind Bindeparameter eine gute Sache.


27
2017-12-01 22:03



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, die select würde zuerst gelaufen werden, gefolgt von der drop Erklärung! Die Nachricht lautet: VERBINDEN SIE WERTE NICHT IN IHR SQL. Verwenden Sie stattdessen Parameter!


24
2017-12-01 21:53



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


16
2017-12-01 21:55



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.


15
2017-12-01 21:56