PDO Prepared Statements: 100% Schutz vor SQL-Injection?

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Die Frage, die jeden PHP-Entwickler quält

\n\n

Wenn du jemals SQL-Abfragen in PHP geschrieben hast, kennst du die goldene Regel: "Nutze PDO und Prepared Statements – dann bist du sicher". Aber stimmt das wirklich? Auf Stack Overflow hat die Frage "Are PDO prepared statements sufficient to prevent SQL injection?" tausende Aufrufe und hitzige Diskussionen gesammelt. Und das zu Recht.

\n\n

In diesem Artikel geben wir nicht einfach ein kurzes "Ja" oder "Nein". Wir schauen unter die Haube von PDO, analysieren, wie Prepared Statements genau funktionieren, und zeigen, in welchen Fällen selbst PDO versagen kann. Bereit? Los geht's.

\n\n

Was ist SQL-Injection und warum ist sie gefährlich?

\n\n

Bevor wir über Schutz sprechen, erinnern wir uns an den Feind. SQL-Injection ist ein Angriff, bei dem ein Angreifer bösartigen SQL-Code über Eingabedaten einschleust. Der Klassiker:

\n\n
// Schlechter Code: Mach das niemals!\n$username = $_POST['username'];\n$query = "SELECT * FROM users WHERE username = '$username'";\n$result = mysqli_query($conn, $query);\n
\n\n

Wenn der Angreifer admin' OR '1'='1 übergibt, wird die Abfrage zu:

\n\n
SELECT * FROM users WHERE username = 'admin' OR '1'='1'\n
\n\n

Schon hast du Zugriff auf Daten ohne Passwort. Und bei '; DROP TABLE users; --? Tschüss, Benutzertabelle.

\n\n

PDO und Prepared Statements: Wie funktioniert das?

\n\n

PDO (PHP Data Objects) bietet den Mechanismus der Prepared Statements. Die Idee ist einfach: Du trennst die Struktur der Abfrage von den Daten. Statt Variablen direkt in den String einzufügen, verwendest du Platzhalter:

\n\n
// Sicherer Code mit PDO\n$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");\n$stmt->execute([':username' => $_POST['username']]);\n
\n\n

Aber was passiert unter der Haube? Das ist der entscheidende Punkt, den viele übersehen.

\n\n

Emulationsmodus vs. native Prepared Statements

\n\n

PDO kann in zwei Modi arbeiten:

\n\n
    \n
  • Emulationsmodus (Standard in älteren PHP-Versionen) – PDO escaped die Daten selbst und setzt sie auf PHP-Seite in die Abfrage ein. Das ist immer noch sicher, aber theoretisch anfällig, wenn das Escaping versagt (z. B. bei ungewöhnlichen Zeichenkodierungen).
  • \n
  • Nativer Modus – PDO sendet zwei Nachrichten an den Datenbankserver: zuerst das Abfrage-Template, dann separat die Daten. Der Server behandelt die Daten als Werte, nicht als Code. Das ist absolut sicher.
  • \n
\n\n

Um den nativen Modus zu aktivieren, deaktiviere die Emulation:

\n\n
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);\n
\n\n

Jetzt wird die Abfrage in zwei Schritten an den Server gesendet. Selbst wenn der Angreifer ' OR '1'='1 übergibt, interpretiert MySQL oder PostgreSQL dies einfach als Zeichenfolge, nicht als SQL-Code. Magie!

\n\n

Aber ist alles perfekt? Fallstricke von PDO

\n\n

Zurück zur Stack Overflow-Frage. Die Antwort "Ja, PDO Prepared Statements reichen aus" – aber mit Einschränkungen. Hier sind Situationen, in denen der Schutz versagen kann.

\n\n

1. Dynamische Bezeichner (Tabellen- und Spaltennamen)

\n\n

Prepared Statements funktionieren nur für Werte (Daten). Wenn du einen Tabellen- oder Spaltennamen einsetzt, helfen Platzhalter nicht:

\n\n
// Gefährlich! Tabellennamen können nicht über Platzhalter übergeben werden\n$stmt = $pdo->prepare("SELECT * FROM :table WHERE id = :id");\n$stmt->execute([':table' => $_GET['table'], ':id' => 1]); // Fehler!\n
\n\n

PDO fügt den Tabellennamen einfach als Zeichenfolge ein, und die Abfrage bricht. Wenn du die Emulation verwendest, könnte ein Angreifer users; DROP TABLE users; -- übergeben. Lösung: Whitelist der erlaubten Werte.

\n\n

2. LIKE-Abfragen und Platzhalterzeichen

\n\n

Wenn du eine

Blogs

Buchempfehlungen