SQL-Injection

·

·

Eine SQL-Injection ist das unerlaubte Einfügen von SQL-Code in eine Anwendung. SQL ist eine Sprache zum Managen von Datenbanken, die häufig von Webseiten und Webanwendungen verwendet wird, um Daten in Datenbanken zu speichern und zu lesen. Durch falsche Implementierung von SQL-Abfragen in PHP, Java oder anderen Sprachen, können Angreifer Datenbanken auslesen und verändern. In manchen Fällen kann durch eine SQL-Injection ein Zugriff zur Shell auf dem Server erlangt werden, über die dann Daten manipuliert und Einstellungen des Servers angepasst werden können, man hat also vollen Zugriff auf den Server.

Funktionsweise

SQL-Injections werden durch Metazeichen von SQL hervorgerufen, es gibt z.B. das Anführungszeichen, Apostroph, Semikolon und den Backslash. Werden Zeichen in ein Eingabefeld wie z.B. eine Suche oder ein Anmelde-Feld eingegeben, so wird meist eine SQL-Abfrage in einer Datenbank mit den eingegebenen Zeichen gestartet. Durch die Eingabe eines Metazeichens wird jedoch die Abfrage verändert und es erscheint meist ein Fehler wie Warning: mysql….

Wenn keine Fehlermeldung zurückgeliefert wird, kann anhand der Antwortzeit erkannt werden, ob die Abfrage funktioniert hat oder ein Fehler aufgetreten ist, dieser Angriff wird auch Blind SQL-Injections genannt.

Wird eine SQL-Abfrage verändert, können neue Abfragen hinzugefügt werden, falls der Datenbankserver das UNION Konstrukt unterstützt, welches dem Angreifer erlaubt nach der ursprünglichen Abfrage eine weiter hinzuzufügen. So können Passwörter und andere Daten ausgelesen werden, deswegen sollten Passwörter immer mit aktuellen Verfahren wie SHA3 gehasht werden, damit selbst wenn ein solcher Angriff möglich ist, die Angreifer die Passwörter nicht lesen können.

Durch die Unterstützung des Befehl SELECT … INTO OUTFILE oder SELECT … INTO DUMPFILE können Angreifer Dateien auf dem Server anlegen und so beliebigen Code einschleusen, vorausgesetzt es ist möglich eine SQL-Injection durchzuführen.

Beispiel: Umgehen von Logins

Auf einem Server gibt es folgende Abfrage:

uName = getRequestString("UserName");
uPass = getRequestString("UserPass");

sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass ="' + uPass + '"'

Diese Abfrage setzt die Variablen uName und uPass in die Abfrage (sql) ein. Dabei sind die Variablen Eingaben des Nutzers auf einer Login Seite, also der Benutzername und das Passwort. Gibt man in das Feld für den Benutzernamen z.B. Manuel und für das Passwort 123456 ein, so würde die Abfrage auf dem Server so aussehen:

SELECT * FROM Users WHERE Name ="Manuel" AND Pass ="123456"

Da diese Abfrage oben auf dem Server nicht überprüft was eingegeben wurde, kann man durch die Eingabe von » or «»=» in beiden Feldern, die Überprüfung in der Datenbank umgehen, denn die Abfrage auf dem Server sähe dann so aus:

SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""

Da «»=»» wie 1=1 immer wahr ist, würde man nun eingeloggt werden für irgendeinen Benutzernamen, meist benötigt man aber mindestens den Benutzernamen, da sonst die Anwendung nicht weiß für welchen Benutzer man eingeloggt werden soll.

 

Beispiel: Datenbanktabelle löschen

Neben dem Umgehen von Authentifizierungen, kann man mit SQL-Injections weitaus grössere Schäden anrichten. Hier mal ein Beispiel:

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

Dieser Code ist eine SQL-Abfrage die in der Tabelle Users nach einer Benutzer-ID sucht. Diese Abfrage sieht erstmal sicherer aus, weil man alles, was in doppelten Anführungsstrichen steht nicht verändern kann, sie ist jedoch ganauso angreifbar wie die obere.

Wenn man in das Feld, welches die Benutzer-ID übergibt folgendes eingibt, kann man die komplette Datenbank löschen, wenn der Server selbst die Rechte dazu hat:

10; DROP TABLE Users

Diese Eingabe wird folgende Abfrage auf dem Server hervorrufen:

SELECT * FROM Users WHERE UserId = 105; DROP TABLE Users

DROP TABLE ist ein Befehl in SQL um eine Tabelle zu löschen, durch das Semikolon nach der ID wird dieser Befehl nach der Abfrage ausgeführt.

 

Neben dem Befehl DROP TABLE, gibt es noch:

  • SHOW TABLES – Zeigt die Tabelle
  • INSERT INTO – Fügt etwas der Tabelle hinzu
  • SELECT – Wählt Daten aus der Tabelle aus
  • LIKE – Mit dem Befehl lassen sich ähnliche Werte finden
  • WHERE – Kann als Filter verwendet werden

Weitere Beispiele von SQL-Injections findest Du unter:

 

Gegenmassnahmen

Eine Regel, die Programmierer immer befolgen sollten lautet: „Vertraue niemals Nutzereingaben“. Wird diese Regel angewandt, und die Nutzereingaben entsprechend auf Metazeichen überprüft oder so eingefügt, dass sie nicht ausführbar sind, sind kaum SQL-Inektionen möglich. Neben der Überprüfung auf Metazeichen, sollten generell keine falschen Eingaben erlaubt werden, wie z.B. bei einem PLZ-Feld die Eingabe von Buchstaben.

Programmierer, die mit SQL arbeiten sollten sich das SQL-Prepared-Statement zunutze machen, welches eine unveränderbare Abfrage bereitstellt, die nur noch mit Variablen gefüllt werden muss. Neben der dadurch erlangten Sicherheit vor SQL-Injections ist die Performance auch besser, weil der Befehl vor dem Aufruf schon kompiliert wurde.

Beispiel ohne Prepared Statement:

$dbh->exec("INSERT INTO REGISTRY (name, value)           

VALUES (".$dbh->quote($name,PDO::PARAM_STR).", ".$dbh->quote($value,PDO::PARAM_INT).")");

Beispiel mit Prepared Statement:

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value)
                       VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

Eine weitere Sicherheitsvorkehrung ist das benutzen von sicheren Passwörtern und nur tatsächlich nötigen Rechten für den Datenbankserver. Manchmal werden Datenbanken mit Standardpasswörter versehen, die sich leicht herausfinden lassen, dass ist verantwortungslos, weil meist in der Datenbank auch personenbezogene Daten und Zugangsdaten der Kunden gespeichert sind.

Möglicherweise können auch Firewalls vor dem Server SQL-Injections erkennen und abwehren, dies ist jedoch nur eine Notlösung und kann als Ergänzung zu den oberen Vorkehrungen angewendet werden.

Heute werden die meisten Webseiten mit Content-Management-Systemen (CMS) wie WordPress oder Magento betrieben. Diese CMS werden häufig gepatcht, weil viele Entwickler an so einem open source Projekt wie WordPress arbeiten und dementsprechend auch häufig Fixes für Fehler und Sicherheitslücken veröffentlichen. Betreibst Du selbst eine Webseite mit einem CMS, so ist zu empfehlen dieses immer schnell zu updaten, denn wenn die Angreifer die Sicherheitslücke kennen, können sie diese auf allen Webseiten mit dem gleichen CMS System meist ausnutzen. Die meisten Sicherheitslücken stecken aber in den Erweiterungen (Plugins), die meist seltener upgedated werden, weil sie von einem einzelnen Entwickler entwickelt werden. Meist ist es besser weniger Erweiterungen installiert zu haben, weil die nicht nur Sicherheitslücken mit sich bringen, sondern manchmal auch einfach nicht mehr weiterentwickelt werden.

Hast Du aber eine selbst entwickelte individuelle Webseite, so kannst Du mit Scannern Lücken für SQL-Injections aufspüren. Eine Liste an solchen Scannern kannst Du auf resources.infosecinstitute.com finden.