PHP-Sicherheit: So schützen Sie Ihre Website vor SQL-Injection und XSS

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

Ihre PHP-Website im Visier: Warum Hacker schwache Sicherheit lieben

\n\n

Stellen Sie sich vor: Sie haben Wochen damit verbracht, einen coolen Blog oder einen Online-Shop mit PHP zu entwickeln. Die Website funktioniert, die Besucher sind zufrieden. Doch eines „schönen" Tages gehen Sie ins Admin-Panel und sehen – nichts. Die Datenbank wurde gelöscht. Oder noch schlimmer: Auf der Startseite prangt Casino-Werbung und alle Benutzer werden auf eine Phishing-Seite weitergeleitet.

\n\n

Kommt Ihnen das bekannt vor? Leider ist dies für viele PHP-Entwickler (nicht nur Anfänger) die Realität. Das Ärgerlichste ist, dass 90 % solcher Angriffe auf zwei scheinbar einfache Schwachstellen zurückzuführen sind: SQL-Injection und Cross-Site-Scripting (XSS). Hacker knacken keine komplexen Verschlüsselungsalgorithmen – sie nutzen lediglich die Unachtsamkeit der Programmierer aus.

\n\n

In diesem Artikel halten wir keine langweiligen Vorträge. Wir werden verstehen, wie diese Angriffe „von innen" funktionieren, und vor allem lernen, wie man zuverlässige Barrieren errichtet. Sie erfahren, wie Sie Ihren PHP-Code zu einer harten Nuss für Angreifer machen. Los geht's!

\n\n

SQL-Injection: Wenn die Datenbank mit der Stimme des Hackers spricht

\n\n

SQL-Injection ist eine Angriffsart, bei der ein Angreifer schädlichen SQL-Code in eine Datenbankabfrage „einschleust". Wenn Ihre Anwendung die eingegebenen Daten nicht filtert, kann der Hacker die Datenbank dazu bringen, jeden beliebigen Befehl auszuführen: vom Diebstahl von Passwörtern bis zur vollständigen Löschung von Tabellen.

\n\n

Wie sieht anfälliger Code aus?

\n\n

Stellen Sie sich ein einfaches Anmeldeformular vor. Der Code eines Anfängers sieht oft so aus:

\n\n
<?php\n$login = $_POST['login'];\n$password = $_POST['password'];\n\n// GEFÄHRLICH! Direkte Einsetzung in die Abfrage\n$query = "SELECT * FROM users WHERE login = '$login' AND password = '$password'";\n$result = mysqli_query($link, $query);\n?>
\n\n

Das scheint logisch. Aber was passiert, wenn der Angreifer im Login-Feld folgende Zeichenfolge eingibt:

\n\n
' OR '1'='1
\n\n

Die Abfrage wird zu:

\n\n
SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '...'
\n\n

Die Bedingung '1'='1' ist immer wahr. Herzlichen Glückwunsch, der Hacker hat sich gerade ohne Passwort im System angemeldet! Und wenn er '; DROP TABLE users; -- eingibt, ist Ihre Benutzertabelle für immer verschwunden.

\n\n

Escaping vs. Prepared Statements: Was ist zu wählen?

\n\n

Viele alte Lehrbücher empfehlen die Verwendung der Funktion mysqli_real_escape_string(). Ja, sie maskiert Sonderzeichen, aber das ist bereits Schnee von gestern. Diese Methode hat Nachteile:

\n\n
    \n
  • Man vergisst leicht, die Funktion auf jede Variable anzuwenden.
  • \n
  • Sie schützt nicht vor allen Arten von Injection (z. B. bei der Arbeit mit LIKE).
  • \n
  • Der Code wird unübersichtlich und schwer zu warten.
  • \n
\n\n

Die moderne und korrekte Methode sind Prepared Statements über PDO oder MySQLi. Sie trennen die Abfragelogik von den Daten. Die Datenbank „kompiliert" zuerst die Abfragevorlage und setzt dann die Daten ein. Selbst wenn der Hacker schädlichen Code übergibt, wird dieser als normale Zeichenfolge und nicht als Teil des SQL-Befehls behandelt.

\n\n

Sicheren Code mit PDO schreiben

\n\n

So sollte eine sichere Datenbankabfrage mit PDO (PHP Data Objects) aussehen:

\n\n
<?php\n// Verbindung zur Datenbank\n$dsn = 'mysql:host=localhost;dbname=mydb;charset=utf8mb4';\n$pdo = new PDO($dsn, 'user', 'password');\n\n// Fehlermodus einstellen (WICHTIG für die Fehlersuche, aber in der Produktion entfernen)\n$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n\n// Abfrage vorbereiten (Vorlage)\n$stmt = $pdo->prepare("SELECT * FROM users WHERE login = :login AND password = :password");\n\n// Parameter binden und ausführen\n$stmt->execute([\n    ':login' => $_POST['login'],\n    ':password' => $_POST['password']\n]);\n\n$user = $stmt->fetch();\n\nif ($user) {\n    echo "Willkommen!";\n} else {\n    echo "Falscher Benutzername oder Passwort";\n}\n?>
\n\n

Üb

Blogs

Buchempfehlungen