Datenschutz in Datenbanken

Dieser Artikel beschäftigt sich mit dem Datenschutz von Datenbanken, die im Zusammenspiel mit Webseiten eingesetzt, welche im eigenen internen Netz als Intranet-Lösung oder im weltweiten Internet angeboten werden.

Damit steht der kriminellen Welt Tür und Tor offen, die Daten, die in der Datenbank gespeichert und eventuell hochsensibel sind, abzugreifen und zu anderen Zwecken zu missbrauchen. Um den Datenschutz in diesen Datenbanken muss man sich also unbedingt kümmern!

Ein weit verbreitetes Mittel um online Daten abzugreifen sind sogenannte SQL-Injections. Das sind bösartige Befehle, die in Datenbankabfragen eingeschleust werden. Der Schutz davor ist komplex und muss somit auf Datenbankebene erfolgen. Unter einer SQL-Injection kann man das Einbringen (das Injizieren) eines schädlichen SQL-Kommandos in die Datenbank verstehen. Häufiges Ziel solcher Angriffe ist neben dem schlichten Verursachen eines Schadens vor allem das Erreichen eines Zugangs zu geschützten Bereichen einer Webanwendung. SQL-Injections sind eine echte Gefahr für Webanwendungen!

Ein Beispiel aus der Praxis zeigt, wie ein solcher Angriff erfolgen kann.

Szenario eines SQL-Injection Angriffs in einer Datenbank

Auf einem Webserver befindet sich eine PHP-Datei mit dem Namen ‚find.php‘ zum Anzeigen von Artikeln eines Warenlagers. Das Skript akzeptiert zum Beispiel einen Parameter ID, welcher später in eine SQL-Abfrage an die Datenbank eingebunden wird.

Der erwartete Webseitenaufruf lautet etwa:
   http://webserver/warenlager/find.php?ID=17

Im Skript wird daraufhin die SQL-Abfrage
   SELECT bezeichnung, preis, bestand FROM artikel WHERE ID=17;
erzeugt und zur Datenbank gesendet.

Problematisch ist dann folgende SQL-Abfrage:
   http://webserver/warenlager/find.php?ID=17;TRUNCATE+TABLE+artikel

In diesem Fall würde im Skript folgende Anweisung an die Datenbank gesendet und ausgeführt werden:
   SELECT bezeichnung, preis, bestand FROM artikel WHERE ID=17;
   TRUNCATE TABLE artikel;

Durch diese Anweisung würde nach der entsprechenden ID gesucht und anschließend die komplette Tabelle «artikel» mitsamt Inhalt gelöscht werden! Sehr gefährlich!

Man sieht, dass man in jedem Fall Vorkehrungen treffen muss, um sich vor solchen Angriffen zu schützen!

Lösung zum Datenschutz in Datenbanken im PHP-Programm

Oft sind solche Problemfälle in PHP-Programmen eingebaut, die Daten in SQL-Datenbanken eintragen. Nimmt ein solches Programm die Maskierung (unbrauchbar machen) nicht korrekt vor, kann ein Angreifer durch den gezielten Einsatz von Funktionen weitere SQL-Befehle einschleusen oder die Abfragen so manipulieren, dass zusätzlich Daten verändert werden oder gar komplett gelöscht werden.

Somit ist auch nicht auszuschließen, das der Angreifer über die entsprechenden Funktionen Zugriff auf den Datenbankserver erhält und sogar ganze Datenbankserver zerstören könnte.

Prepared Statements

Für die Maskierung von SQL-Abfragen kann man sich durch die Verwendung von Prepared Statements (vorbereitete Anweisungen) im PHP-Code zu schützen. Dies geschieht in der Benutzung der Klasse mysqli_stmt.

Die Arbeit mit vorbereiteten Anweisungen verläuft im Gegensatz zur konventionellen Vorgehensweise in mehreren Schritten:

Vorbereitete Anweisungen haben beim wiederholten Aufruf von Abfragen einen Performance-Vorteil. Der Ablauf eines Prepared Statements:

  1. Eine SQL-Abfrage wird mit Platzhaltern für die variablen Bestandteile versehen an das RDBMS geschickt.
  2. Das RDBMS prüft die Abfrage.
  3. Wenn die Prüfung erfolgreich war, puffert4) das RDBMS die Abfrage für die spätere Verwendung und liefert eine Referenz auf die Abfrage zurück.
  4. Über diese Referenz werden die Platzhalter mit „echten“ Werten gefüllt und an das RDBMS geschickt.
  5. Abschließend wird die Abfrage mit den konkreten Werten ausgeführt.

Der Geschwindigkeitsvorteil entsteht dadurch, dass das RDBMS eine Abfrage auch bei vielfachem Aufruf nur einmal prüfen muss und dass jeweils nur noch die variablen Bestandteile (die Werte der Variablen für die Platzhalter) an das RDBMS übertragen werden müssen.

Der Datenschutz in Datenbanken erfolgt dadurch, dass bei Prepared Statements das geprüfte Template gepuffert vorliegt und nur ganz bestimmte variable Bestandteile zulässt. Sollte also ein SQL-Kommando eingeschleust werden, das nicht dem Prepared Statement entspricht, fällt das sofort auf und es wird entsprechend nicht ausgeführt.

Beispiel mit Prepared Statements

//id aus der URL entnehmen
$id=$_GET['id'];

//Die SQL-Abfrage
if ($stmt = $mysqli -> prepare("SELECT bezeichnung, preis, bestand FROM artikel WHERE id = ?")) {
   $stmt -> bind_param('i',$id);
   $stmt -> execute();
   $stmt -> bind_result($bezeichnung, $preis, $bestand);
   $stmt -> fetch();

   //Das Ergebnis der Abfrage anzeigen
   echo "Bezeichnung: $bezeichnung
   Preis: $preis
   Bestand: $bestand";

   //Die Verbindung zur Datenbank schliessen
   $stmt -> close();
}

Ablauf des Prepared Statements

(Schritt 1) $mysqli -> prepare(„SELECT bezeichnung, preis, bestand FROM artikel WHERE id = ?“)

Mit der Methode prepare() des mysqli-Objekts bereitet die Anweisung für die Ausführung vor. Sie liefert im Erfolgsfall ein Objekt vom Typ mysqli_stmt und andernfalls false zurück. Als Parameter wird das SQL-Kommando übergeben. Besonders interessant ist hier die WHERE-Klausel, denn hier wird anstelle eines konkreten Wertes als Platzhalter ein Fragezeichen eingesetzt. Der Platzhalter wird später durch den Wert einer Variablen ersetzt.

(Schritt 2) $stmt -> bind_param(‚i‘,$id);

Der Platzhalter ? wird durch den Wert der Variablen ‚$id‘ ersetzt. Das geschieht mit der Methode bind_param() des mysqli_stmt-Objekts. Man spricht in diesem Zusammenhang von binden. Als ersten Parameter wird der Methode bind_param() ein String aus einzelnen Zeichen übergeben. Jedes dieser Zeichen beschreibt den Datentypen einer zu bindenden Variablen. Danach folgen durch Kommas getrennt die Bezeichner der zu bindenden Variablen. In dem Beispiel muß nur eine Variable ‚$id‘ vom Typ Integer ‚i‘ ersetzt werden.

(Schritt 3) $stmt -> execute();

Das SQL-Statement ist bisher vorbereitet und an den Parameter gebunden. Die Methode execute führt die vorbereitete Abfrage aus. Diese liefert einen Wahrheitswert zurück. Die Ergebnismenge liegt dann in der Variablen $stmt.

(Schritt 4) $stmt -> bind_result($bezeichnung, $preis, $bestand);

Wie zuvor kurz erwähnt, muß bei dieser Vorgehensweise zunächst das Ergebnis an Variablen gebunden werden, über die anschließend mit den eigentlichen Daten gearbeitet werden kann. Die Methode heißt bind_result(). Die Parameter dieser Methode sind eine Liste der Variablen, an die das Ergebnis angebunden werden.

(Schritt 5) $stmt -> fetch();

Anschließend wird die Ergebnismenge abgerufen. Die Methode fetch() stellt die Datensätze aus der Ergebnismenge zeilenweise in den gebundenen Variablen zur Verfügung. Bedingt durch die Formulierung der Beispielabfrage, gibt es hier nur 1 Datensatz als Ergebnismenge. Bei anderen Abfragen erhält man entsprechend auch andere Ergebnisse.

Bewahrung des Datenschutzes durch Prepared Statements

Diese Vorgehensweise bannt die Gefahr der einfachen SQL-Injection, wie sie im oberen Abschnitt besprochen wurde.

Am Anfang ist die Zuweisung:
$id = 17;

Die Zuweisung nun ändern in:
$id = „17; DROP TABLE artikel“;

Das oben angegebene Skript ausführen und man sieht, dass die Ausführung zu keinen Problemen führt!

Die Anweisung
$id = „17; DROP TABLE artikel“;
entspricht nicht der vorgegebenen Schablone, welche eine ganze Zahl für den Platzhalter erwartet.

Die Vorbereitung der gefährlichen Anweisung wird nicht durchgeführt und als Ergebnis ein ‚false‘ zurückgeben!

Die Anforderungen an Datenschutz in Datenbanken nach DSGVO

In Datenbanken sind Vorkehrungen zum Schutz zu treffen, damit die Datenbank den Regelungen der DSGVO entspricht.

1. Datenschutz in Datenbanken durch Technikgestaltung

Im ersten Schritt ist der Art. 25 DSGVO zu beachten. Hier geht es um Datenschutz durch Technikgestaltung und durch datenschutzfreundliche Voreinstellungen. In diesem Artikel wird beschrieben, dass

2. Datenaufbewahrung und Datenlöschung

Im nächsten Schritt wird der Art. 17 Abs. 1 DSGVO (Recht auf Löschung, Recht auf Vergessenwerden) angewendet, welcher verpflichtet dass Daten gelöscht werden, wenn kein Zweck mehr für die Verarbeitung gegeben ist und auch sonst keine Ausnahme (Art. 17 Abs. 3) vorliegt. Eine Rekonstruktion von gelöschten Daten in Datenbanken soll nicht mehr möglich sein. Versehentlich gelöschte Daten zuerst sperren und anschließend zu einem festgelegten Zeitpunkt definitiv löschen (Soft-Delete-Funktion).

Diese Möglichkeit der Einschränkung der Daten ohne sie endgültig zu löschen, ist eine Vorgabe von Art. 18 DSGVO (Recht auf Einschränkung der Verarbeitung). Betroffene Personen haben nach Art. 18 DSGVO das Recht, die Einschränkung der Verarbeitung zu verlangen.

Auch Aufbewahrungsfristen und Löschen von betroffenen Datensätzen beachten, denn ansonsten kann gegen gesetzlich vorgegebene Datenspeicherfristen verstossen werden.

3. Datenexport

Nach Art. 20 DSGVO (Recht auf Datenübertragbarkeit) sollte die Datenbank eine Exportfunktion anbieten, die personenbezogene Daten in einem «interoperablen Format» exportieren kann.

Dies ist noch nicht abschließend geklärt, aber man sollte Formate wie XML oder JSON, welche beides gängige Datenaustauschformate sind, vorsehen.

4. Sicherheit der Verarbeitung

Laut Art. 24 und Art. 32 DSGVO sind technisch-organisatorische Maßnahmen in einer Datenbank umzusetzen. Zumindest folgende Funktionalitäten sind bereitzustellen: