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
SQL-Injection bei XKCD
SQL-Injection auf der Straße
SQL-Injection
Benutzereingaben im SQL-StatementSELECT * 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;