Zum Inhalt springen

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 anzeigenkostet 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.

Zurück zum Kalender