SQL-Injection (dt. SQL-Einschleusung) bezeichnet das Ausnutzen einer Sicherheitslücke in Zusammenhang mit SQL-Datenbanken, die durch mangelnde Maskierung oder Überprüfung von Metazeichen in Benutzereingaben entsteht. Der Angreifer versucht dabei, über die Anwendung, die den Zugriff auf die Datenbank bereitstellt, eigene Datenbankbefehle einzuschleusen. Sein Ziel ist es, Daten auszuspähen, in seinem Sinne zu verändern, die Kontrolle über den Server zu erhalten oder einfach größtmöglichen Schaden anzurichten.
Auftreten
SQL-Injections sind dann möglich, wenn Daten wie beispielsweise Benutzereingaben in den SQL-Interpreter gelangen. Denn Benutzereingaben können Zeichen enthalten, die für den SQL-Interpreter Sonderfunktion besitzen und so Einfluss von außen auf die ausgeführten Datenbankbefehle ermöglichen. Solche Metazeichen in SQL sind zum Beispiel der umgekehrte Schrägstrich (Backslash), das Anführungszeichen, der Apostroph und das Semikolon.
Oft sind solche Lücken in CGI-Skripten und in Programmen zu finden, die Daten wie Webseiteninhalte oder E-Mails in SQL-Datenbanken eintragen. Nimmt ein solches Programm die Maskierung nicht korrekt vor, kann ein Angreifer durch den gezielten Einsatz von Funktionszeichen weitere SQL-Befehle einschleusen oder die Abfragen so manipulieren, dass zusätzliche Daten verändert oder ausgegeben werden. In einigen Fällen besteht auch die Möglichkeit, Zugriff auf eine Shell zu erhalten, was im Regelfall die Möglichkeit zur Kompromittierung des gesamten Servers bedeutet.
Gegenmaßnahmen
Eine Maßnahme besteht darin, Daten die Bedeutung für den SQL-Interpreter zu nehmen. Zu diesem Zweck wird oft zum Ausfiltern oder Maskieren (sogenanntem Escapen) von Metazeichen in Benutzereingaben gegriffen. Hierdurch kann die Gefahr der SQL-Injection gemildert oder beseitigt werden.
Generell ist die Webanwendung für die korrekte Prüfung der Eingabedaten verantwortlich, so dass vor allem die Metazeichen des betreffenden Datenbanksystems entsprechend zu maskieren sind, die für Ausnutzung dieser Sicherheitslücke verantwortlich sind. Weitergehend können auch die Eingabedaten auf die Eigenschaften erwarteter Werte geprüft werden. So bestehen deutsche Postleitzahlen beispielsweise nur aus Ziffern. Geeignete Schutzmaßnahmen sind in erster Linie dort zu implementieren.
Der simplere und sicherere Weg ist jedoch, die Daten überhaupt vom SQL-Interpreter fernzuhalten. Dabei kann man auf das Kappen der Eingabe verzichten. Die Technik dazu sind gebundene Parameter in Prepared Statements. Dabei werden die Daten als Parameter an einen bereits kompilierten Befehl übergeben. Die Daten werden somit nicht interpretiert und eine SQL-Injection verhindert. Als positiven Nebeneffekt bekommt man bei bestimmten Datenbanken (z. B. Oracle) außerdem eine Steigerung der Performance. Stored Procedures bieten dagegen keinen generellen Schutz vor SQL-Injection, insbesondere dann nicht, wenn der SQL-Code der Funktion nicht bekannt ist.
Doch auch auf Seiten des Datenbankservers lassen sich Sicherheitsvorkehrungen treffen. So sollten die Benutzer, mit denen sich eine Webanwendung beim Datenbankserver authentifiziert, nur die Privilegien besitzen, die er tatsächlich benötigt. So können zumindest einige der möglichen Angriffe unwirksam werden.
Hat ein Betreiber eines Webservers keine Kontrolle über die Anwendungen, kann durch Einsatz von Web Application Firewalls (WAF) zumindest teilweise verhindert werden, dass SQL-Injection-Schwachstellen ausgenutzt werden können. Unabhängig von der Kontrolle über die Anwendungen kann ein Betreiber eines Webservers durch den gezielten Einsatz einer WAF die Sicherheit zusätzlich erhöhen, da viele WAFs neben abwehrenden auch prophylaktische Maßnahmen anbieten.
Es ist nicht schwer, bestehende Programme so umzubauen, dass SQL-Injections 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.
PHP
In PHP steht zu diesem Zweck für fast jede verwendete Datenbank eine Escape-Funktion bereit. Nur die Oracle-Anbindung besitzt keine solche Escape-Funktion, hingegen können dort Prepared Statements verwendet werden, was beispielsweise bei der beliebten MySQL-Datenbank erst mit den Funktionen von MySQLi möglich geworden ist.
Ein Beispiel für MySQL:
$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!");
Eine weitere Möglichkeit ist die Typumwandlung von Übergabeparametern.
$abfrage = "SELECT spalte1
FROM tabelle
WHERE spalte2 = " . intval($_POST['spalte2Wert']);
$query = mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");
Ab PHP 5.1 sollten PHP Data Objects für Datenbankabfragen verwendet werden.
$dbh->exec("INSERT INTO REGISTRY (name, value)
VALUES (".$dbh->quote($name,PDO::PARAM_STR).", ".$dbh->quote($value,PDO::PARAM_INT).")");
Oder als Prepared Statement:
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
Häufig wird aus Bequemlichkeit einfach die Konfigurationsoption „magic_quotes_gpc“ auf „on“ gestellt, mit der von außen kommende Benutzereingaben automatisch maskiert werden. Doch dies ist nicht empfehlenswert. Denn manche nicht selber programmierte Skripte setzen eigenständig Funktionen wie etwa addslashes() oder das bereits weiter oben genannte mysql_real_escape_string() ein. Das heißt, dass bereits allen relevanten Zeichen in den Benutzereingaben durch so genannte Magic Quotes ein Backslash vorangestellt wurde und nun durch die Escape-Funktion erneut ein Backslash vorangestellt wird.
Somit werden die Benutzereingaben verfälscht und man erhält beispielsweise anstatt eines einfachen Anführungszeichens ein Anführungszeichen mit vorangestelltem Backslash (\“). Auch aus Gründen der Portabilität sollte bei der Entwicklung von Anwendungen auf diese Einstellung verzichtet und stattdessen alle Eingaben manuell validiert und maskiert werden, da nicht davon ausgegangen werden kann, dass auf allen Systemen dieselben Einstellungen vorherrschen oder möglich sind.
Darüber hinaus sollte addSlashes() nicht zum Maskieren von Datenbank-Eingaben benutzt werden, da es keine ausreichende Sicherheit gegenüber mysql_real_escape_string() gewährleistet.
Quelle: Wikipedia: (http://de.wikipedia.org/wiki/SQL-Injection)