Wie funktioniert SQL Injection?
Wird serverseitig auf die Datenbank zugegriffen, werden häufig Daten/Informationen von Usern mit in die Abfrage eingebaut. Wenn der User die Daten/Eingabe so manipuliert, dass diese einen Datenbankcode ergeben, so kann sich der User Zugriff auf die Datenbank verschaffen.
Einfaches Beispiel:
Eine Website, auf welcher Websitebesucher uns einen Gästebucheintrag hinterlassen können.
Diese Felder können verwendet werden, um den Datenbankcode zu ändern und kontrolliert auf die Datenbank zugreifen zu können.
Wie schütze ich mich vor SQL Injection?
Serverseitig
Niemals und wirklich nie den Eingaben eines Users vertrauen.
Prepared Statements
Im Backend und beim Zugriff auf die Datenbank Prepared Statements verwenden.
Bei Prepared Statements wird vorab der Zugriff definiert, wobei die Daten/Parameter separat in die Abfrage hinzugefügt werden. Beim Hinzufügen werden diese auf Richtigkeit überprüft und bereinigt.
Nahezu alle Programmiersprachen bieten Frameworks bzw. Erweiterungen an, um den Zugriff auf Datenbanken über Prepared Statements zu ermöglichen. Hier gilt, stets aktuelle Technologien auf dem neuesten Stand und richtig zu verwenden, um die Sicherheit der Daten zu gewährleisten.
Beispiel für PHP:
PHP-Beispiel, bei dem keine Prepared Statements verwendet werden und der User somit die Möglichkeit hat, auf die Datenbank zuzugreifen. (Die Parameter werden direkt und ohne Überprüfung in die Datenbankabfrage eingebaut.)
'''php
$message = $_POST["message"];
$from = $_POST["from"];
$query = "INSERT INTO 'guestbook' ('message', 'from') VALUES ('$message', '$from')";
$pdo->query($query);
'''
Verwendung von Prepared Statements mittels PHP Data Objects (PDO) extension. Die Parameter/die Eingaben des Users werden separat in die Abfrage eingebaut.
'''php
$message = $_POST["message"];
$from = $_POST["from"];
$query = "INSERT INTO 'guestbook' ('message', 'from') VALUES (:message, :from)";
$statement = $connection->prepare($query);
$statement->bindParam(':message', $message, PDO::PARAM_STR);
$statement->bindParam(':from', $from, PDO::PARAM_STR);
$result = $statement->execute();
'''
Beispiel näher betrachtet:
Unsere Website verwendet im Hintergrund eine einfache Datenbank mit zwei Tabellen. Eine für Gästebuch-Einträge und eine für unsere User.
Werden keine Prepared Statements für den Datenbankzugriff verwendet, haben Websitebesucher eine Möglichkeit, auf unsere Datenbank zuzugreifen (wie im ersten Codebeispiel für PHP).
Bob fügt einen normalen Eintrag ein
Alice löscht den Eintrag von Bob
Mittels SQL Injection schafft Alice es, den Eintrag von Bob wieder zu löschen.
Alice kopiert alle User in das Gästebuch
Mittels SQL Injection kann Alice Einträge von einer Tabelle in eine andere kopieren.
Nun sind alle Userdaten für alle Seitenbesucher sichtbar!
Werden im Backend Prepared Statements verwendet...
... sieht ein Angriffsversuch von Alice wie folgt aus:
Der vermeintliche Code, welcher eine Tabelle löschen würde, wird einfach als Text in die Datenbank gespeichert.
Relevante Vorfälle
Unter anderem wurden folgende große Unternehmen Ziel eines SQL-Injection-Angriffs:
- ThePirateBay | 2010 | 4 Millionen User-Details geleakt
- Sony Pictures | 2011 | 1 Million Accounts geleakt
- Yahoo | 2012 | 450.000 Plaintext-Passwörter geleakt
Weitere Maßnahmen
- Regelmäßig Updates der Datenbank erstellen, um vor einem Verlust von Tabellen und Daten geschützt zu sein.
- Niemals Passwörter in Plaintext speichern. Hashe die Passwörter und vergleiche die Hash-Werte bei der Authentifikation.
- Encrypted Storage: Relevante und kritische Daten in der Datenbank verschlüsseln.
- Frameworks und Erweiterungen wie auch das Backend immer am aktuellen Stand halten.
- Datenbanken sowie Dumps (=Backups) nie öffentlich zugängig machen.