Ihre PHP-Website im Visier: Warum Hacker schwache Sicherheit lieben
\n\nStellen 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\nKommt 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\nIn 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\nSQL-Injection: Wenn die Datenbank mit der Stimme des Hackers spricht
\n\nSQL-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\nWie sieht anfälliger Code aus?
\n\nStellen 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\nDas scheint logisch. Aber was passiert, wenn der Angreifer im Login-Feld folgende Zeichenfolge eingibt:
\n\n' OR '1'='1\n\nDie Abfrage wird zu:
\n\nSELECT * FROM users WHERE login = '' OR '1'='1' AND password = '...'\n\nDie 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.
Escaping vs. Prepared Statements: Was ist zu wählen?
\n\nViele 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
- 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
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\nSicheren Code mit PDO schreiben
\n\nSo 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