SQL Injection (zu deutsch SQL-Injektion) bezeichnet das Ausnutzen einer Computersicherheits-Lücke. Der Angreifer versucht SQL-Abfragen zu manipulieren. Hierzu werden über die Applikation, die den Zugriff auf die Datenbank bereitstellt, SQL Statements eingefügt.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 einzuschleusen 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 muss in Zeichenfolgen das '-Zeichen und in einigen Datenbanken zusätzlich der \ durch voranstellen eines umgekehrten Schrägstriches maskiert werden: \' bzw. \\. Außerdem muss sichergestellt werden, dass Zahlen nur aus Ziffern und dem Dezimaltrennzeichen bestehen.Stored Procedures sind in diesem Zusammenhang sicherer. 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.Veränderung von DatenAuf 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 Beispiele sollen 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/cgi-bin/find.cgi?ID=42;UPDATE%20USER%20SET%20TYPE="admin"%20WHERE%20ID=23 Erzeugtes SQL SELECT author, 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.Datenbank Server verändernAuf einem Webserver findet sich das Script search.aspx zum Suchen nach Webseiten. Das Script akzeptiert den Parameter keyword, welcher später Bestandteil des SQL-Befehls wird. Keine SQL-Injektion Aufruf http://webserver/search.aspx?keyword=sql Erzeugtes SQL SELECT url, title FROM myindex WHERE keyword LIKE '%sql' SQL-Injektion Aufruf http://webserver/search.aspx?keyword=sql' GO EXEC cmdshell('format C') — Erzeugtes SQL SELECT url, title FROM myindex WHERE keyword LIKE '%sql' GO EXEC cmdshell('format C') –' Hier wird der eigentlichen Abfrage ein weiterer Befehl angehängt. Die zwei Bindestriche (–) kommentieren das Hochkomme als Überbleibsel der eigentlichen Anfrage aus. Der Befehl ermöglicht das Formatieren der Festplatte, aber auch Downloads oder ähnliches lassen sich dadurch erzeugen (am Beispiel Microsoft SQL Server).Ausspähen von DatenAuf 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/cgi-bin/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 CodeEine 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 Betriebssystems oder des Datenbankservers für denselben beschreibbar ist (wenn dieser z.B. als root läuft), beliebigen Code auf dem System auszuführen.Zeitbasierte AngriffeWenn 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');[bearbeiten]GegenmassnahmenEs 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:Microsoft .NET FrameworkIm .NET Framework gibt es einfache Objekte, mit denen man solche Probleme umgeht.AnstattSqlCommand cmd = new SqlCommand("SELECT spalte1 FROM tabelle WHERE spalte2 = '" + spalte2Wert + "';");sollte folgendes verwendet werdenstring spalte2Wert = "Mein Wert";SqlCommand cmd = new SqlCommand("SELECT spalte1 FROM tabelle WHERE spalte2 = @spalte2Wert;");cmd.Parameters.Add("@spalte2Wert", spalte2Wert);JavaSQL Injection kann leicht durch bereits vorhandene Funktion verhindert werden. In Java wird zu diesem Zweck die PreparedStatement Klasse verwendet.AnstattStatement stmt = con.createStatement();ResultSet rset = stmt.executeQuery("SELECT spalte1 FROM tabelle WHERE spalte2 = '" + spalte2Wert + "';");sollte folgendes verwendet werdenPreparedStatement pstmt = con.prepareStatement("SELECT spalte1 FROM tablle WHERE spalte2 = ?");pstmt.setString(1, spalte2Wert);ResultSet rset = stmt.executeQuery();PHPIn PHP wird zu diesem Zweck die Funktion mysql_real_escape_string() (http://www.php-homepage.de/manual/function.mysql-real-escape-string.php) verwendet.Anstatt$abfrage = "SELECT spalte1 FROM tabelle WHERE spalte2 = '".$_POST['spalte2Wert']."'";$query = @mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");sollte folgendes verwendet werden$abfrage = "SELECT spalte1 FROM tabelle WHERE spalte2 = '".mysql_real_escape_string($_POST['spalte2Wert'])."'";$query = @mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");PerlDas datenbankunabhängige Datenbankmodul DBI (http://search.cpan.org/~timb/DBI-1.43/) 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( $spalte2Wert );MS-SQLÜber parametrisiertes Kommando kann die Datenbank vor SQL-Code-Injection geschützt werden: SELECT COUNT(*) FROM Users WHERE UserName=? AND UserPassword=?[bearbeiten]ORACLE (dynamic PL/SQL)Die Benutzung von "bind variables" kann neben der Überprüfung der Eingabe-Parameter helfen
Dr. Simon Schmitt
Medizininformatiker :: Arzneimitteltherapiesicherheit :: Software as a Medical Device :: LEGO Serious Play Facilitator :: NLP Coach