Immer häufiger entstehen Schwachstellen in Web-Applikationen, weil die Entwickler versäumen Ihre Software gegen die Manipulation von außen durch entsprechende Techniken abzusichern. Eine häufig benutze Angriffsmethode stellt dabei die so genannte SQL-Injektion dar.

Mit der entsprechenden Sorgfalt und auch einem gewissen Mehraufwand ist man allerdings hat man als Entwickler allerdings durchaus die Möglichkeit sich bzw. Seine Anwendung gegen SQL-Injektion zu schützen.

Wie SQL-Injektion funktioniert

Bei der SQL-Injektion werden Benutzer eingaben unzureichend oder gar ungefiltert in eine Datenbankabfrage verkettet. Dabei verwendet der Angreifer Zeichenketten, die von einem SQL-Server als Anweisung verstanden werden können. Für ihn ist es dabei von Vorteil, wenn er möglichst viel über die Interne Datenbank-Stuktur der jeweiligen Applikation kennt. OpenSource-Projekte, sind aus diesem Grund besonders anfällig für diese Art des Angriffs. Prinzipiell sind alle Programmiersprachen, die als Backend hinter der Web-Applikation stehen verwundbar. Allerdings gibt es bei einigen Sprachen Mechanismen, die verhindern sollen, dass es zu SQL-Injektionen kommen kann. Mit ein wenig Sorgfalt kann man aber in nahezu jeder Programmiersprache die Möglichkeit für eine potenzielle SQL-Injektion minimieren.

Beispiel für SQL-Injektion in PHP

Angenommen ein PHP-Programmierer möchte einen Datensatz aus einer SQL-Basierten Datenbank abfragen:

Die ID möchte er nun via GET-String übertragen:

http://www.meinhost.com/kunde/?id=1
SELECT * FROM user WHERE ID = {$_GET['id']}

Solange tatsächlich die ID im GET-String übertragen wird funktioniert alles bestens. Weiß der Angreifer aber etwas mehr über die Datenbank-Struktur, weiss er z.B. auch, dass es in der Tabelle ein Feld „admin“ gibt, worüber das Skript identifiziert, ob jemand Administrator-Rechte hat. Ein Möglicher GET-String könnte z.B. folgendermaßen aus sehen:

http://www.meinhost.com/kunde/?id=1;UPDATE+user+SET+admin+=+1+WHERE id+=+1;

Die resultieren SQL-Abfrage wäre dann:

SELECT * FROM user WHERE ID = 1;UPDATE user SET admin = 1 WHERE id = 1;

Das Semikolon wird als Trennzeichen zwischen zwei Abfragen aufgefasst. Somit werden bei der obenstehenden Abfrage eigentlich zwei Abfragen ausgeführt.
Wie man sieht, kann auf diese Weise jeder seinen eigenen Datensatz sehr schnell zu einem Administrator machen.

Häufige Fehler und Schutzmechanismen gegen SQL-Injektion

Einige Fehler beim Umgang mit Datenbanken im Zudammenhang mit Webapplikationen werden leider immer wieder gemacht. Dabei ist es eigentlich sehr einfach diese zu vermeiden:

Ein potenzieller Angreifer muss um Erfolgreich zu sein möglichst viel über die Datenbank-Struktur herausbekommen. Sehr häufig kann man in POST-Formularen folgenden Aufbau erkennen:

<form action="" method="post">
	<input type="text" name="username" />
	<input type="text" name="passwort" />
	<input type="text" name="strasse" />
	<input type="text" name="ort" />
usw.
</form>

Die Datenbank hat dann meistens Felder, die genau so heißen wie die Input-Felder in der HTML-Datei.

Dementsprechend leiten sich meine ersten beiden Tipps zu Vermeidung von SQL-Injektion ab:

  • Benutze niemals die gleichen Namen für Felder in einer Datenbank und in einem Formular!
  • Verwende möglichst Feldnamen, die zwar logisch aber nicht einfach zu erraten sind!

Letzterer Tipp lässt sich zum Beispiel durch die Verwendung von Präfixen für die Spaltennamen realisieren.

Beispielsweise würde ich eine Beziehung des Präfixes zur Tabelle herstellen. Das Feld „username“ aus dem obigen Beispiel könnte dann user_username heißen. Bewährt haben sich auch verkürzte Präfixe, die mehrere willkürliche Buchstaben des Tabellennamen enthalten. So könnte aus dem Feld „id“ der Tabelle „herkunft“ „hrft_id“ werden. Diese Art der Feldnamen hat übrigens noch den weiteren Vorteil, dass wenn die Präfixe in einer Datenbank eindeutig gewählt werden als Fremdschlüssel auf einen Blick mit der verweisenden Tabelle in Verbindung gebracht werden können.

Darüber hinaus sollte man jegliche Daten, die vom User an den Server geschickt werden einer Filterung unterziehen. In den meisten Fällen sind von vorn herein nicht alle Zeichen für alle Datenfelder erlaubt. So könnte man Beispielsweise definieren, dass für den Benutzernamen nur Buchstaben und Ziffern akzeptiert werden. So könnte man für die meisten Datenfelder direkt einen Filter definieren. Dazu bietet es sich an, sofern man in einer objektorientieren Programmiersprache arbeitet für die Eingabe-Felder Klassen zu erzeugen, die dann wiederverwendet und bei Problemen entsprechend Zentral modifiziert werden können.

Viele Programmiersprachen bieten die Möglichkeit die Zeichenketten bevor sie in die Abfrage eingefügt werden auszumaskieren. So würde diese Technik die Injektion von oben in folgende Zeichenkette umwandeln:

SELECT * FROM user
WHERE ID = 1\\;UPDATE\\ user\\ SET\\ admin\\ \\=\\ 1\\ WHERE\\ id\\ \\=\\ 1\\;

Damit würde zwar die Anweisung einen Fehler erzeugen weil das Feld ID (in der Regel) ein Integer sein sollte, aber das wäre immerhin schon einmal besser als den „Schadcode“ auszuführen.

Die beste und sicherste Methode SQL-Injektionen zu verhindern bzw. minimieren ist die Verwendung eines Datenbank-Framworks (wie z.B. Creole für PHP). Dabei werden in die Abfrage selbst nur Platzhalter für Dateneingaben eingefügt. Über eine Methode können diese Platzhalter dann durch die eigentlichen Daten ersetzt werden und entsprechend ihres Datentyps ausmaskiert werden. Sollte es dann doch einmal zu einem Problem kommen, kann dieser Fehler in dieser Software behoben und neu eingespielt werden ohne, dass seine eigenen Programme modifizieren muss.

Wenn man alle diese Tipps beachtet entwickelt man eine robuste Datenbank Anwendung, die wenigstens die Gefahr einer SQL-Injektion auf ein verträgliches mass minimieren kann.

These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Technorati
  • MisterWong
  • del.icio.us
  • Digg
  • BlinkList
  • Furl