SQL-Injection

SQL-Injection – Grundlagen

  • Kontext
    • Anwendung benutzt eine Datenbank
    • SQL-Kommandos werden dynamisch aufgrund von Eingaben erzeugt
  • Schwachstelle
    • Eingaben werden nicht validiert bevor sie in SQL-Anweisungen eingehen
    • Dynamisches SQL wird durch Verketten von Eingaben erzeugt
  • Angriff
    • Angreifer modifiziert Eingaben so, dass das SQL-Statement in unerwünschter Weise verändert wird
    • WHERE-Bedingung wird modifiziert
    • Neue Statements werden ausgeführt
  • Ergebnis
    • Unberechtigter Zugriff auf Daten (C und I aus CIA)
    • Veränderung von Daten

Beispiel für SQL-Injection

UNO-Webseite gehackt
UNO-Webseite gehackt

SQL-Injection bei XKCD

XKCD zu SQL-Injection
XKCD zu SQL-Injection

SQL-Injection auf der Straße

SQL-Injection auf der Straße
SQL-Injection auf der Straße

SQL-Injection

Benutzereingaben im SQL-Statement
SELECT * FROM users WHERE username = [userInput]

Java-Beispiel

String sql = "SELECT * FROM users WHERE username = '"
             + userInput + "'";
Statement stmt = cn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

SQL-Injection: Beispiele

userInput = "thomas"

SELECT * FROM users WHERE username = 'thomas'
userInput = "thomas' OR '1'='1"

SELECT * FROM users WHERE username = 'thomas' OR '1'='1'
userInput = "thomas'; DROP TABLE users; SELECT * FROM passwords --";

SELECT * FROM users WHERE username = 'thomas';DROP TABLE users;
SELECT * FROM passwords-- '

Vermeidung von SQL-Injection

Grundsätzlich keine SQL-Statements durch Stringverkettung mit Benutzereingaben erzeugen

Statt dessen Prepared Statements verwenden

  • Anfang und Ende des Parameters klar festgelegt
  • Datenbanktreiber escaped Daten korrekt
  • Programmieraufwand steigt nur minimal
  • Richtig eingesetzt kann sogar die Performance steigen

SQL-Injection: Vermeidung (Java)

Problematische Version

String sql = "SELECT * FROM users WHERE username = '"
             + userInput + "'";
Statement stmt = cn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

Sichere Variante mit Prepared Statements

String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = cn.prepareStatement(sql);
pstmt.setString(1, userInput);
ResultSet rs = pstmt.executeQuery();

Beispiel: Unsichere Variante in PHP

$dbh = new PDO("mysql:host=$host;dbname=$dbName", $user, $pwd);

$q = "SELECT * FROM studenten WHERE nachname = '"
        . $_GET['name'] . "'";

$stmt = $dbh->query($q);

while ($row = $stmt->fetch()) {
    echo $row["id"], " ", $row["nachname"], " ";
    echo $row["vorname"], "<br/>";
}

$stmt = null;
$dbh = null;

Beispiel: Sichere Variante in PHP

$dbh = new PDO("mysql:host=$host;dbname=$dbName", $user, $pwd);

$q = "SELECT id, nachname, vorname "
        . "FROM studenten WHERE nachname = ?";

$stmt = $dbh->prepare($q);

$stmt->bindValue(1, $_GET['name']);
$stmt->execute();

while ($row = $stmt->fetch()) {
    echo $row["id"], " ", $row["nachname"], " ";
    echo $row["vorname"], "<br/>";
}

$stmt = null;
$dbh = null;

Copyright © 2025 Thomas Smits