tuerchen 06 · 6. Dezember
Prepared, aber nicht ganz
Finde den BugMittelPHP 8.4
Aufgabe
Die Jobsuche nutzt brav prepare() und benannte Parameter. Trotzdem meldet der Pentest eine SQL-Injection über die Query-Parameter von $q (kommt direkt aus $_GET). Wo ist das Loch?
<?php
function findJobs(PDO $pdo, array $q): array
{
$sql = 'SELECT id, title FROM jobs WHERE city = :city AND salary >= :min';
$sort = $q['sort'] ?? 'created_at';
$dir = strtoupper($q['dir'] ?? 'desc') === 'ASC' ? 'ASC' : 'DESC';
$sql .= " ORDER BY {$sort} {$dir}";
$sql .= ' LIMIT ' . (int) ($q['limit'] ?? 20);
$stmt = $pdo->prepare($sql);
$stmt->execute([
'city' => $q['city'] ?? '',
'min' => $q['min'] ?? 0,
]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
- a`$dir`: Die Sortierrichtung landet ungeprüft im SQL.
- b`$sort`: Der Spaltenname wird direkt in `ORDER BY` eingesetzt.richtig
- c`LIMIT`: Der Wert wird per Verkettung statt als Parameter eingefügt.
- d`execute()`: `:city` und `:min` werden nicht escaped, weil `PDO::quote()` fehlt.
Tipp anzeigenTipp ausblendenkostet keine Punkte
Prepared Statements schützen nur Werte. Welche Teile eines SQL-Statements sind keine Werte – und wie kommen sie hier ins SQL?
Mitraten geht mit deinem kostenlosen Entwicklerkonto
Lesen darf jeder. Punkte, Bestenliste und Preise gibt es nur mit Konto.
Auflösung
Richtig ist b.
Platzhalter gibt es nur für Werte, nicht für Bezeichner wie Spaltennamen oder Schlüsselwörter. Darum wird $sort per String-Interpolation eingesetzt – und damit kann ein Angreifer beliebige Ausdrücke in ORDER BY schmuggeln, etwa eine Unterabfrage, deren Ergebnis die Sortierung umdreht. So lassen sich Daten Bit für Bit auslesen (Blind SQL Injection).
Die anderen Stellen sind sicher: $dir kann nur ASC oder DESC werden, LIMIT ist per (int) gecastet, und gebundene Parameter brauchen kein quote().
Fix: eine Allowlist, z. B. $sort = in_array($q['sort'] ?? '', ['created_at', 'salary', 'title'], true) ? $q['sort'] : 'created_at'; Siehe PHP-Handbuch: SQL-Injection.