Zum Inhalt springen

SQL-Injection

aus Wikipedia, der freien Enzyklopädie
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 12. Juli 2004 um 12:33 Uhr durch LuckyStarr (Diskussion | Beiträge) (Perl). Sie kann sich erheblich von der aktuellen Version unterscheiden.

SQL Injection (zu deutsch deutsch SQL Injektion) bezeichnet das Ausnutzen einer Computersicherheits-Lücke. Der Angreifer versucht SQL Abfragen zu manipulieren. Hierzu wird über die Applikation, die den Zugriff auf die Datenbank bereitstellt, SQL Statments einzufügen.

Oft zu finden sind SQL Injection Lücken in CGI Scripten, aber auch Programme die andere Daten, etwa Webseiteninhalte oder E-Mails in SQL Datenbanken eintragen sind anfällig. Es wird versucht, weitere SQL Anforderungen einzuschleußen oder die Abfragen so zu manipulieren, dass man zusätzliche Daten erhält. Manche Datenbanksysteme bieten auch die Möglichkeit Zugriff auf eine Shell zu erhalten, womit der ganze Server kompromitierbar wird.

SQL Injection Bugs treten auf, wenn eine Applikation SQL Abfragen an den Server weiterreicht, ohne benutzerveränderbare Parameter mit Fluchtzeichen zu versehen. So sollten z.B. die Zeichen '  ; " durch \' \; \" ersetzt werden.

Stored Procedures sind In einem Programm übergibt man die Benutzereingaben den Stored Procedures, erst hier wird eine SQL Query erzeugt und ausgeführt. Die Stored Procedures sind deshalb besonders sicher, da sie keine weiteren SQL Befehle in Benutzereingaben akzeptieren.

Vorgang

Veränderung von Daten

Auf einem Webserver findet sich das Script find.cgi zum Anzeigen von Artikeln. Das Script akzeptiert den Parameter ID welcher später Bestandteil des SQL-Befehls wird. Folgende Tabelle soll dies illustrieren:

  Keine SQL-Injektion
Aufruf http://webserver/cgi-bin/find.cgi?ID=42
Erzeugtes SQL SELECT author, subjekt, text FROM WHERE artikel ID=42
  SQL-Injektion
Aufruf http://webserver/find.cgi?ID=42;UPDATE%20USER%20SET%20TYPE="admin"%20WHERE%20ID=23
Erzeugtes SQL SELECT authur, subjekt, text FROM artikel WHERE ID=42; UPDATE USER SET TYPE="admin" WHERE ID=23

Wie man erkennen kann, wird dem Programm ein zweiter SQL-Befehl untergeschoben, der die Benutzertabelle modifiziert.

Ausspähen von Daten

Auf manchen SQL Implementationen ist die UNION Klausel verfügbar. Diese erlaubt es, mehrere SELECTs gleichzeitig abzusetzen, die dann eine gemeinsame Ergebnis-Menge zurückliefern. Durch eine geschickt untergeschobene UNION Klausel kann man beliebige Tabellen und Systemvariablen auslesen.

  Keine SQL-Injektion
Aufruf http://webserver/cgi-bin/find.cgi?ID=42
Erzeugtes SQL SELECT text FROM WHERE artikel ID=42
  SQL-Injektion
Aufruf http://webserver/finduser.cgi?ID=42%20UNION%20SELECT%20login,%20password,%201%20FROM%20user
Erzeugtes SQL SELECT author, subjekt, text FROM artikel WHERE ID=42 UNION SELECT login, password, 1 FROM user

Die 1 beim UNION SELECT ist nötig, weil alle mit UNION verknüpften SELECTs die gleiche Anzahl von Spalten haben müssen. Der Angreifer muss also wissen wieviele Spalten die ursprüngliche Abfrage hat.

Einschleusen von beliebigen Code

Eine weniger bekannte Variante stellt auch gleichzeitig die potentiell gefährlichste dar. Wenn der Datenbankserver die Kommandos SELECT ... INTO OUTFILE bzw. SELECT ... INTO DUMPFILE unterstützt, können diese Kommandos dazu benutzt werden Dateien auf dem Dateisystem des Datenbankserver abzulegen. Theoretisch ist es dadurch möglich, falls das Bibliotheksverzeichnis des Betriebsystems oder des Datenbankservers für denselben beschreibbar ist (wenn dieser z.B. als root läuft), beliebigen Code auf dem System auszuführen.

Zeitbasierte Angriffe

Wenn der Datenbankserver Benchmark Funktionen unterstützt kann der Angreifer diese dazu nutzen um Informationen über die Datenbankstruktur in Erfahrung zu bringen. In Verbindung mit dem if Konstrukt sind der Kreativität des Angreifers kaum Grenzen gesetzt.

Das folgende Beispiel pausiert auf einem MySQL Datenbankserver mehrere Sekunden falls der gegenwärtige User root ist:

SELECT if( user() like 'root@%', benchmark(100000,sha1('test')), 'false');

Gegenmassnahmen

Es ist nicht schwer bestehende Programme so umzubauen, dass SQL-Injektionen nicht mehr möglich sind. Das hauptsächliche Problem der meisten Programmierer ist fehlendes Wissen über diese Art von Angriffen. Nachfolgend einige Beispiele um die Angriffe abzuwehren.

Java

SQL Injection kann leicht durch bereits vorhandene Funktion verhindert werden. In Java wird zu diesem Zweck die PreparedStatement Klasse verwendet.

Anstatt

Connection con = (acquire Connection)
Statement stmt = con.createStatement();
ResultSet rset = stmt.executeQuery("SELECT spalte1 FROM tabelle WHERE spalte2 = '" + spaltenName + "';");

sollte folgendes verwendet werden

Connection con = (acquire Connection)
PreparedStatement pstmt = con.prepareStatement("SELECT spalte1 FROM tablle WHERE spalte2 = ?");
pstmt.setString(1, spaltenName);
ResultSet rset = stmt.executeQuery();

PHP

In PHP wird zu diesem Zweck die Funktion mysql_escape_string() verwendet.

Anstatt

$abfrage = "SELECT spalte1 FROM tabelle WHERE spalte2 = '".$_POST['spaltenname']."'";
$query = @mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");

sollte folgendes verwendet werden

$abfrage = "SELECT spalte1 FROM tabelle WHERE spalte2 = '".mysql_escape_string($_POST['spaltenname'])."'";
$query = @mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");

Perl

Das datenbankunabhängige Datenbankmodul DBI unterstützt eine ähnliche "prepare" Syntax die auch im Java Beispiel zu sehen ist.

$statementhandle = $databasehandle->prepare("SELECT spalte1 FROM tabelle WHERE spalte2 = ?");
$returnvalue = $statementhandle->execute( $spaltenname );

Siehe auch