SQL-Injection verstehen, erkennen und verhindern

Ein Wort der Warnung

Wenn Sie von einer gehackten Website hören, denken Sie möglicherweise immer noch an einen Typen mit Kapuzenpullover in einem Hightech-Bunker (oder im Keller seiner Mutter), der im Rahmen koordinierter Angriffe über seine Tastatur Tausende entfernter Rechner steuert, während ununterbrochen Zeichenfolgen wie bei http://hackertyper.com/ über den Bildschirm flimmern.

bog

Wahrscheinlich denken Sie eher nicht: „Ich habe im Browser am Ende der URL ein paar Zeichen eingefügt und begehe jetzt ein Kapitalverbrechen, weil ich unerlaubt auf ein Computersystem zugreife.“

Und genau deshalb nehmen wir uns an dieser Stelle Zeit für den Hinweis, dass SQL-Injections oft Auswirkungen haben, die in keinem Verhältnis zum Aufwand der Ausführung stehen.

Was würden Sie davon halten, wenn ein neuer IT-Mitarbeiter sagt: „Es ist doch nur ein Befehl, was soll da schon groß passieren?“ Die praktischen Aspekte rund um SQL-Injections sollte man jedenfalls genauso ernst nehmen.

Als Systemadministrator in einem mittelgroßen Unternehmen, gibt es vermutlich ein halbes Dutzend interner Anwendungen, die im Tagesgeschäft ständig gebraucht werden und

Warum SQL-Injections eine Rolle spielen

Informationen in einer Datenbank werden in der Regel auch heute noch mit der ein oder anderen standardisierten Abfragesprache (wie beispielsweise SQL) eingefügt, gefiltert und abgerufen. Webanwendungen werten bei fast jedem Seitenaufruf unzählige SQL-Abfragen aus, ganz gleich, ob es sich um eine rudimentäre Hobby-Website mit einer kleinen SQLite-Datei handelt oder um eine gefragte E-Commerce-Seite mit Millionen von Besuchern pro Stunde, für die Anbieter von Datenbanksystemen riesige Cluster von Datenbankservern zur Verfügung stellen.

Ein Webbrowser, SQL-Grundkenntnisse und eine Internetverbindung reichen also aus, um Schwachstellen einer Webanwendung ausnutzen und Benutzerdaten abzugreifen, Anmeldeinformationen ausfindig zu machen oder zurückzusetzen und die gewonnenen Daten als Ausgangsbasis für umfangreichere Angriffe auf das Netzwerk zu nutzen.

Um zu verstehen, wie eine SQL-Injection funktioniert beziehungsweise wie man Schwachstellen ausnutzt, muss man sich zunächst die Grundlagen von SQL ins Gedächtnis rufen.

SQL und Systemadministratoren

Wenn ein Bewerber, zu dessen künftigen Aufgaben als Systemadministrator das Aufsetzen eines neuen Windows-Domänenservers und einiger Dateiserver gehört, im Vorstellungsgespräch erklärt, mit Dateien habe er bisher eigentlich noch nicht wirklich gearbeitet, würde sein Lebenslauf sofort im Papierkorb landen.

Wenn ein Bewerber behauptet, er könne einen Exchange-Server aufsetzen, später aber gesteht, bislang kaum mit E-Mails zu tun gehabt zu haben, würden Sie seinen Lebenslauf… eben, in den Papierkorb werfen.

Leider ist es immer noch gang und gäbe, dass Systemadministratoren SQL-Server einrichten und verwalten, obwohl sie wenig oder gar keine praktische Erfahrung mit dem Erstellen von Abfragen oder der Datenbearbeitung durch SQL-Befehle haben.

Um Schwachstellen in den eigenen Anwendungen zu erkennen und SQL-Injections zu verhindern, muss man unbedingt ein gewisses Grundlagenwissen in Sachen SQL mitbringen.

Was ist SQL?

Wer noch nichts selbst in SQL geschrieben hat, lässt sich leicht zu der Annahme verleiten, SQL sei „dieses Ding, mit dem man Daten aus einer Datenbank herausholt“. Doch wer Möglichkeiten und Komplexität von SQL unterschätzt, stolpert leicht über eines der zahlreichen Sicherheitsprobleme, die häufig auftreten, wenn eine Webanwendung mit einer SQL-Datenbank kommuniziert.

Auch wenn es meist übersehen wird: SQL ist eine eigenständige Programmiersprache mit vollem Funktionsumfang. Jede noch so abstruse Idee, die irgendein leichtsinniger Programmierer irgendwann einmal gehabt hat, ist schon mit irgendeiner SQL-Version umgesetzt worden.

Wahrscheinlich wäre es tatsächlich besser, den Begriff „Abfrage“ jedes Mal durch „Befehl“ zu ersetzen. Vor allem, wenn man die Führungsebene eines Unternehmens von den potenziell gravierenden Auswirkungen von SQL-Injections überzeugen will, klingt „Durch diese Schwachstelle können Angreifer willkürlich Befehle auf dem Server ausführen“ sehr viel eindrucksvoller als der lapidare Hinweis, dass sie Berichte über die Unternehmensdaten erstellen können.

Um das zu veranschaulichen, zeigen wir Ihnen einige der kuriosen Dinge, die man mit SQL bewerkstelligen kann:

SQL-Kreisdiagramme: http://code.openark.org/blog/mysql/sql-pie-chart

pie

SQL-Abfragen, die als Webbrowser fungieren: https://github.com/pramsey/pgsql-http

SQL-Abfragen zum Durchsuchen des Server-Dateisystems: http://hubpages.com/technology/Using-xp_cmdshell-to-Query-the-Windows-File-System

Der Begriff „Abfrage“ wird offensichtlich im Alltag ganz anders verwendet als im Kontext einer SQL-Injection. Normalerweise wird eine Abfrage für eine Frage gehalten: „He, kannst du mir mal den Ball zuwerfen?“ Bei SQL ist mit einer „Abfrage“ eher etwas in der Art gemeint: „Ich werfe dir gerade einen 160 km/h schnellen Ball an den Kopf.“

Zum Mitmachen

Eine der bemerkenswertesten Eigenschaften von SQL ist, dass die Ausdrucksweise sich seit seiner Erfindung Anfang der 1970er-Jahre nicht wesentlich verändert hat. Zwar werden manche der etwas esoterisch anmutenden Befehle von den großen Datenbankanbietern anders gehandhabt als in Open-Source-Anwendungen, doch die grundlegenden Befehle sind fast überall dieselben.

Behalten Sie das im Hinterkopf, falls Sie die unten aufgeführten Schritte selbst ausprobieren möchten. Über die Links können Sie eine SQLite-Datenbank mit den Daten herunterladen, auf die in diesem Artikel Bezug genommen wird, und ein plattformunabhängiges Open-Source-Abfragetool zur Verwendung mit der Beispieldatei, DB Browser for SQLite .sql

Beispiel-SQLite-Datenbankdatei: YeOldeCheeseShoppe.zip herunterladen
DB Browser for SQLite: http://sqlitebrowser.org/

SQLite ist zwar so ziemlich die kleinste Datenbank, die es für den Alltagsgebrauch gibt (wenn ihr Funktionsumfang auch nur ein wenig geringer wäre, könnte man die Daten einfach gleich in Dateien speichern), doch die Datenbanksprache SQL selbst ist bei allen Systemen sehr ähnlich.

Was ist eine Datenbanktabelle?

Wenn Sie plötzlich damit betraut würden, einen Käsestand mit dem Namen „Ye Olde Cheese Shoppe“ auf dem örtlichen Bauernmarkt zu eröffnen, dazu aber keinen Computer verwenden dürften, dann würden Sie wahrscheinlich auf die gute alte Listen-Methode zurückgreifen und aufschreiben, welche Ware Sie zu welchen Preisen anbieten würden usw.

In einer Datenbank werden solche Listen „Tabellen“ genannt. Sie bilden die Grundlage für die Strukturierung der Daten in der Datenbank. Im Grunde ist eine Tabelle lediglich eine Liste mit Informationen. Es ist hilfreich, sich Datenbanktabellen wie die Tabellen in einer Kalkulationstabelle, zum Beispiel einer Excel-Datei, vorzustellen. Jede Tabelle stellt eine Liste dar und die Spalten dieser Tabelle sind die Attribute der einzelnen Elemente dieser Liste.

Eine Kalkulationstabelle mit den Daten des Marktstands

graph

Dieselben Informationen in einer Datenbanktabelle

graph2

Wir werden die Struktur der oben abgebildeten Produkttabelle für die Beispiele unten heranziehen.

Wie sehen die grundlegenden SQL-Befehle aus?

Daten wandern nicht auf magische Weise in eine Datenbank. Mithilfe von SQL-Befehlen werden die Informationen in den Tabellen erstellt, gelesen, aktualisiert und gelöscht. Die meisten Webanwendungen und Webframeworks funktionieren nach diesem Prinzip. Sie stellen eine grafische Oberfläche zur Verfügung über welche die zugrunde liegenden Daten bearbeitet werden können.

Es ist wichtig, diese Befehle zu kennen, denn SQL-Injections basieren darauf, dass der Angreifer die erwarteten Vorgänge verändert und Schutzmechanismen umgeht.

Ein Hinweis zur SQL-Syntax
Es hat sich eingebürgert, die Befehlswörter in SQL-Anweisungen groß und die Wörter, die sich je nach Anweisung ändern (Tabellennamen, Eigenschaften usw.), klein zu schreiben.

Erstellen und Aktualisieren von Daten mit SQL

Die Daten werden mithilfe des SQL-Befehls INSERT in eine Tabelle geladen. Im Allgemeinen sieht die Struktur so aus:

INSERT INTO
“Ihr-Tabellenname”
(Spalte_Name_1, Spalte_Name_2)
VALUES
(Wert_für_Spalte_Name_1, Wert_für_Spalte_Name_2)

Will man ein neues Produkt zur Produkttabelle (die wie die Kalkulationstabelle oben strukturiert ist) hinzufügen, sieht die Anweisung folgendermaßen aus:

INSERT INTO
products
(name, sku, units, weight, price)
VALUES
(‘Alsace’, 303403, 3, 1.2, 300)

Um ein weiteres Produkt hinzuzufügen, führt man den Befehl INSERT erneut aus, und ändert die Werte entsprechend den Produkteigenschaften:

INSERT INTO
products
(name, sku, units, weight, price)
VALUES
(‘Bravino’, 409504, 6, 3.7, 250)

Der SQL-Befehl UPDATE funktioniert ganz ähnlich:

UPDATE
products
SET
Spalte_Name_2 = neuer_Wert
WHERE
Spalte_Name_1 = irgendein_Wert

So könnten wir zum Beispiel eine Käsesorte umbenennen:

UPDATE
products
SET
name = ‘Zutacular’
WHERE
name = ‘Bravino’

Lesen von Daten mit SQL

Daten aus den Tabellen werden mithilfe des Befehls SELECT ausgegeben.

SELECT
(Spalte_Name_1, Spalte_Name_2)
FROM
Ihr-Tabellenname

So sieht es aus, wenn Sie den Befehl SELECT auf die Produkttabelle anwenden:

SELECT
(name, sku, units, weight, price)
FROM
products

Im Ergebnis werden alle Daten aus der Produkttabelle ausgegeben.

Löschen von Daten mit SQL

DELETE FROM
Ihr-Tabellenname
WHERE
Spalte_Name_1 = Ihr_Wert

Durch den folgenden Befehl werden alle Inhalte der Produkttabelle gelöscht:

DELETE FROM
products
WHERE
name = name

Auswählen von Daten mit SQL

SELECT-Anweisungen halten viele Optionen bereit und können sehr komplex sein. Eine Option, die man unbedingt kennen sollte, ist das Filtern (Hinzufügen von Bedingungen, um nur die gewünschten Reihen einer Tabelle anzuzeigen). Denn genau hier setzt die gängigste Art einer SQL-Injection an.

Es ist höchst unwahrscheinlich, dass für jede Seite der Website des Käsestands die Daten jeder einzelnen Käsesorte benötigt werden. Daher können Sie die Daten mit der WHERE-Klausel filtern.

Im Allgemeinen wird die WHERE-Klausel so verwendet (an die vorherige SQL-Anweisung angefügt):

SELECT
(Spalte_Name_1, Spalte_Name_2)
FROM
Ihr-Tabellenname
WHERE
Spalte_Name_1 = ?

Mit der WHERE-Klausel lassen sich Vergleiche anstellen, darin liegt ihre eigentliche Stärke.

Will man die Abfrage an die Tabelle anpassen, sieht das beispielsweise so aus:

SELECT
(name, sku, units, weight, price)
FROM
products
WHERE
name = ‘Bravino`

Verkettung von Zeichenfolgen: Die Wurzel allen Übels?

Programmierer bezeichnen eine Abfolge nicht numerischer Zeichen als „string“ oder in deutsch als „Zeichenfolge“. Allgemein bekannt ist allerdings, dass die Verkettung von Zeichenfolgen (unter Programmierern auch „Konkatenation“ genannt, eine Bezeichnung für das Aneinanderhängen kurzer Zeichenfolgen, aus denen so eine längere entsteht) eine schnelle und einfache Möglichkeit ist, SQL-Anweisungen zusammenzusetzen.

Nehmen wir an, Sie haben die Webanwendung mit nur zwei Vorlageseiten eingerichtet:

  1. eine Startseite (Indexseite), auf der sämtliche Käsesorten aufgelistet werden
  2. eine „Zeig mir den Käse“-Seite, an die der Indexwert der Käsesorte übermittelt wird, wenn jemand auf der Startseite auf den entsprechenden Link klickt

URL: /show_me_the_cheese?id=1

Der Indexwert „1“ wird an die Webanwendung übermittelt, die aus dem benötigten Teil des Befehls und dem Indexwert, der sich bei jeder Seiten-URL ändert, eine SQL-Abfrage zusammensetzt.

sql_string = “SELECT * FROM products WHERE id = ” + id

Anschließend hat die Variable sql_string folgenden Inhalt:

SELECT * FROM products WHERE id = 1

Der Inhalt der Variable sql_string wird dann an die Datenbankbibliothek übergeben, die die gewünschte Käsesorte findet und zurückgibt, sodass sie auf der Webseite angezeigt werden kann. So funktioniert es bei der Webanwendung. Alternativ kann man die vollständige oben stehende SQL-Abfrage kopieren, sie in einem SQL-Client einfügen und auf die Datenbank anwenden.

result = DB.run_query(sql_string)

Das sieht auf den ersten Blick nicht besonders gefährlich aus, weshalb SQL-Injections auch gerne unterschätzt werden. Die Verkettung von Zeichenfolgen aus SQL-Anweisungen ist aber leider der schnellste Weg zu einer gehackten Website.

Der Konkatenation ist es ganz gleich, was Sie übergeben. Sie weiß nicht, wie eine „id“ auszusehen hat. Wenn also ein Betrüger den „id“-Wert in der URL von „1“ zu

URL: /show_me_the_cheese?id=(UPDATE products SET price = 0.1 WHERE id = 1)

ändert, wird der Code der Webanwendung weiterhin ausgeführt wie bisher:

sql_string = “SELECT * FROM products WHERE id = ” + id

Nur, dass die Variable sql_string diesmal den folgenden Wert hat:

SELECT * FROM products WHERE id =
(UPDATE products
SET price = 0.1
WHERE id = 1)

Das ist eine hundertprozentig gültige SQL-Anweisung. Die Unterabfrage, durch die der Indexwert „1“ ersetzt worden ist, wird als erstes ausgeführt. Die Folge für unseren virtuellen Käsestand: jeder kann jetzt für zehn Cent so viele Bravino bestellen, wie er will.

Wie verhindern Webframeworks eine SQL-Injection?

Webframeworks werden in der Regel eingesetzt, um produktiver zu arbeiten, und enthalten meist bewährte Sicherheitsfunktionen für die jeweilige Programmiersprache. Im Allgemeinen verhindern Webframeworks eine SQL-Injection, indem sie einfache Methoden zur Datenabfrage zur Verfügung stellen, sodass Entwickler nicht in Versuchung geraten, leicht angreifbare SQL-Anweisungen aus verketteten Zeichenfolgen zu schreiben.

Sie führen zwei wichtige Aufgaben aus:

Zum einen bieten sie spezielle Möglichkeiten um Benutzereingaben zu bereinigen, mit denen sich häufige SQL-Injection-Muster abwehren lassen: Das Framework entfernt das Zeichen NULL, Zeilenumbrüche, einzelne Anführungszeichen usw., die häufig dazu genutzt werden, in der ursprünglichen Abfrage zusätzliche SQL-Befehle unterzubringen.

Zum anderen stellen sie eine Syntax zur Verfügung, um zu deklarieren, wie eine SQL-Anweisung aussehen sollte, bevor sie tatsächlich ausgeführt wird. Der Name unterscheidet sich je nach Framework, doch die dahinter liegende Absicht ist immer dieselbe: Bevor die SQL-Anweisung ausgeführt wird soll sichergestellt werden, dass das Format korrekt ist.

Bei Rails sieht der Unterschied so aus:

# SQL String Concatenation BAD
Model.where(“id = “ + id)

bzw.

# Parametized Query Good
Model.where(“id = ?”, id)

Das zweite (und korrekte) oben aufgeführte Format bewirkt eine automatische Bereinigung des „id“-Werts, der von der URL übermittelt wurde, und die Zusammensetzung einer korrekten, sicheren SQL-Abfrage. Dieses Muster existiert in nahezu allen Webframeworks:

Wo SQL-Injections am ehesten auftreten

In der Vergangenheit waren vor allem große Webanwendungen von SQL-Injections (die es seit der Erfindung der HTML-Tags gibt) betroffen. Wie so vieles haben sich auch SQL-Injections seit den Anfängen des Webs weiterentwickelt. Zum einen in technischer Hinsicht und zum anderen im Hinblick auf die Benutzer.

Formularbeginn

Die benutzerbezogene Entwicklung besteht einfach darin, dass inzwischen eine Milliarde Menschen online ist und die meisten sich mit Browsern und den allgemeinen Begrifflichkeiten rund um das Internet besser auskennen als mit irgendeiner anderen Art von Rechnerschnittstelle.

In technischer Hinsicht war das die Entwicklung von SQLite, einer frei zugänglichen portablen Datenbank, die für Einsatzbereiche wie die Entwicklung mobiler Anwendungen, das Internet der Dinge, Netzwerkgeräte und alle möglichen anderen Spielereien geeignet ist, die früher eine schlecht formatierte Textdatei als Speichermechanismus genutzt hätten.

Diese Entwicklungen sind dafür verantwortlich,

Deshalb sieht unsere Welt heute so aus:

Hubs für Smart Homes

Smart-Home-Hubs sind angreifbar. Wenn die Anmeldeinformationen überschrieben werden, können Angreifer das Opfer mithilfe seines eigenen Sicherheitssystems ausspionieren.

Netzwerkgeräte

Wenn sie erst einmal gehackt worden sind, bilden Netzwerkgeräte wie Router und Switches eine wunderbare Ausgangsbasis für das weitere Vordringen der Angreifer in das Netzwerk.

Schicke Elektro-Sportwagen

car

Bislang wurden bei solchen Autos nur die Konten gehackt. Es ist aber durchaus denkbar, dass die Fahrzeuge künftig nicht nur im Rahmen einer ganz normalen modernen Diebstahlsicherung sondern durch eine SQL-Injection per Remotezugriff angehalten oder gefährlichere Funktionen implementiert werden. Andere Hersteller sind bereits per Fernzugriff gehackt worden.

Android-Apps

Wenn die entsprechende App gehackt worden ist, sind private Fotos und Kontakte gefährdet.

iOS-Apps

Die Vernetzung mobiler Anwendungen und der APIs, von denen sie abhängen, sind ein neuer Angriffspunkt für SQL-Injections.

Wie können Webserver helfen?

Apache

ModSecurity bietet standardmäßig eine Reihe von Basisregeln, die einfache SQL-Injections verhindern (und ist auch mit nginx und IIS kompatibel).

nginx

Testen Sie das Open-Source-Tool Naxsi, eine Web Application Firewall (WAF), die sich wie ein nginx-Modul eines Drittanbieters verhält und etliche der bekannten Auswirkungen von SQL-Injections blockiert.

Die voreingestellten SQL-Injection-Regeln von Naxsi verhindern beispielsweise den URL-Parameter `—-` (die SQL-Kommentarzeichenfolge, die häufig für Angriffe genutzt wird).

Internet Information Server

IIS ist ab Version 7.0 (das umfasst so ziemlich jede IIS-Version, die Sie im Tagesgeschäft noch guten Gewissens verwenden können) in der Lage, eingehende HTTP-Anforderungen zu filtern.

Im offiziellen IIS-Blog finden sich Anweisungen wie man HTTP-Vorfilter hinzufügt:

Ist NoSQL sicher vor SQL-Injections?

NoSQL ist ein Allerweltsbegriff für eine Vielzahl von Speichertechnologien, die die herkömmlichen relationalen Datenbankmanagementsysteme (RDBMS: Server, auf denen Daten in Tabellen gespeichert sind, die miteinander in Beziehung stehen und über SQL-Abfragen abgerufen werden) ergänzen oder ersetzen. Diese vereinfachten Speichersysteme werden manchmal als „Dokumentendatenbanken“ oder „Schlüssel-Wert-Speicher“ bezeichnet und ermöglichen stellenweise schnellere Lese- und Schreibvorgänge.

Es ist nicht uninteressant, sich anzusehen, wie umfassende NoSQL-Speichersysteme wie MongoDB, Redis, Memsql, Cassandra usw. mit Angriffen umgehen, die zwar streng genommen keine SQL-Injections, aber doch ähnlich strukturiert sind.

Die meisten NoSQL-Lösungen sind sehr viel aktueller als SQL und verzichten auf überflüssige Funktionen. Das macht sie für Angriffe natürlich weniger anfällig.

green

Ein gutes Beispiel ist MongoDB: Die Daten lassen sich ausschließlich über Binary-JSON(BSON)-Anforderungsobjekte aus der Datenbank abfragen. Es ist schlicht nicht möglich, einfach irgendwelche zusammengesetzten Zeichenfolgen zu übergeben, die von SQL-Injection-Anweisungen durchsetzt sind.

Doch Vorsicht: Es ist durchaus jederzeit möglich, ausführbaren JavaScript-Code als Teil eines BSON-Abfrageobjekts einzuschleusen. Man muss sich gut überlegen, welches Risiko man eingehen will.

https://docs.mongodb.com/manual/faq/fundamentals/#javascript

Was weder für noch gegen RDBMS spricht: Ein Webdienst mit verschiedenen Abstraktionsschichten in Form von Anwendungen, Speicherung und Code wird immer Schwachstellen und Sicherheitslücken haben, die sich ausnutzen lassen.

Im Allgemeinen werden grundlegende SQL-SELECT-Anweisungen also nicht von Angreifern genutzt, um durch verkettete Unterabfragen Schaden anzurichten. Aber es gibt durchaus andere, ganz ähnliche Probleme, gegen die Sie sich wappnen sollten.

Defense-in-Depth-Checkliste: Schutz vor SQL-Injections

chart

Checkliste im PDF-Format herunterladen

Wie immer, wenn es um IT-Sicherheit geht, ist der einzige wirkliche Schutz eine Verteidigung in der Tiefe durch Defense-in-Depth-Lösungen: einander ergänzende Sicherheitsmaßnahmen auf mehreren Ebenen, die zusammen einen übergeordneten Schutzmechanismus bilden.

Die folgende Checkliste hilft dabei, den Ausführungspfad einer Anwendungsabfrage nachzuverfolgen und zu erkennen, wo man zusätzliche Sicherheitsebenen einbauen kann:

Datenbank

Anwendung

Webserver/Web Application Firewall

Weitere Informationen

SQL-Injections sind nur eine Möglichkeit, die beängstigende Zahl von Schwachstellen auszunutzen, die viel zu viele Webanwendungen aufweisen.

Im kostenlosen Kurs von Troy Hunt, Betreiber der Website https://haveibeenpwned.com/, erfahren Sie mehr über XSS, CSRF und andere Angriffsmethoden.

Error: No site found with the domain 'test.basti1012.bplaced.net' (Learn more)