„Ich escapen doch nur Anführungszeichen“: Warum Ihr Code verwundbar ist
\n\nWenn Sie jemals gegoogelt haben „How can I sanitize user input with PHP?“, sind Sie nicht allein. Diese Frage auf Stack Overflow hat Hunderttausende von Aufrufen. Kein Wunder: Das Thema Sicherheit ist eines der heißesten in der Webentwicklung.
\n\nAber hier ist das Paradoxon: Die meisten Antworten auf diese Frage sind entweder veraltet oder gefährlich. Entwickler schreiben immer noch Dinge wie mysql_real_escape_string() (das es seit 10 Jahren nicht mehr gibt) oder entfernen einfach „gefährliche“ Zeichen. Spoiler: Das funktioniert nicht.
In diesem Artikel analysieren wir die Top-5-Fehler bei der Bereinigung von Benutzereingaben in PHP, die Ihre Website zu einem Sieb machen, und zeigen Ihnen, wie Sie sie ein für alle Mal beheben.
\n\nFehler Nr. 1: Blindes Vertrauen in „Bereinigung“ als Allheilmittel
\n\nDer größte Fehler ist zu glauben, es gäbe eine einzige Funktion, die alle Daten „säubert“. Hier ist typischer Anfängercode:
\n\n<?php\n$name = $_POST['name'];\n$name = strip_tags($name);\n$name = addslashes($name);\n// Sind die Daten jetzt sicher? Nein!\n?>\n\nDas Problem ist, dass verschiedene Kontexte unterschiedliche Verarbeitung erfordern. Validierung (Formatprüfung) und Bereinigung (Säuberung) sind nicht dasselbe. Und dann gibt es noch das Output-Escaping, das an einer ganz anderen Stelle stattfindet.
\n\nSo sollte es sein: Definieren Sie, was Sie mit den Daten in jedem Schritt tun. Für die Datenbank etwas anderes, für HTML etwas anderes, für JSON wieder etwas anderes.
\n\nFehler Nr. 2: Verwendung veralteter Funktionen (oder deren falsche Anwendung)
\n\nGehen wir die „Dinosaurier“ der PHP-Sicherheit durch:
\n\n- \n
mysql_real_escape_string()– entfernt in PHP 7.0. Vergessen Sie es. \n addslashes()– schützt nicht vor allen SQL-Injection-Angriffen, besonders bei Multibyte-Kodierungen. \n strip_tags()– entfernt Tags, escapet aber keine Ausgabe. XSS ist immer noch über Attribute möglich. \n
Ein Beispiel für gefährlichen Code, der immer noch vorkommt:
\n\n<?php\n$id = $_GET['id'];\n$id = addslashes($id);\n$query = \"SELECT * FROM users WHERE id = '$id'\";\n// Wenn id = 1 OR 1=1 -- wurden Sie gehackt\n?>\n\nSo sollte es sein: Verwenden Sie vorbereitete Anweisungen (Prepared Statements). Das ist der einzig zuverlässige Weg, um sich vor SQL-Injection zu schützen.
\n\n<?php\n$stmt = $pdo->prepare(\"SELECT * FROM users WHERE id = :id\");\n$stmt->execute(['id' => $_GET['id']]);\n?>\n\nSehen Sie? Keine Bereinigung für SQL. Nur Parameter. Die Datenbank selbst entscheidet, was Daten und was ein Befehl ist.
\n\nFehler Nr. 3: Verwechslung von Validierung und Bereinigung
\n\nViele denken: „Ich entferne alle verdächtigen Zeichen, dann ist es sicher.“ Aber das zerstört die Logik der Anwendung. Stellen Sie sich vor, ein Benutzer gibt das Passwort P@ssw0rd! ein, und Sie entfernen die Zeichen @ und !. Das Passwort wird zu Pssw0rd – und der Benutzer kann sich nicht mehr anmelden.
Validierung prüft, ob die Eingabe dem erwarteten Format entspricht (E-Mail, Zahl, URL). Wenn nicht, wird sie abgelehnt.
\n\nBereinigung entfernt oder ändert unerwünschte Zeichen, aber nur, wenn es wirklich nötig ist (z. B. für einen Dateinamen).
\n\nBeispiel für eine korrekte E-Mail-Validierung:
\n\n<?php\n$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);\nif ($email === false) {\n // E-Mail ist ungültig – nicht speichern, nicht ausgeben\n echo \"Geben Sie eine gültige E-Mail-Adresse ein\";\n exit;\n}\n// Jetzt ist $email ein sicherer String für alle Zwecke\n?>\n\nGoldene Regel: Wenn Sie eine Zahl erwarten, prüfen Sie, ob es eine Zahl ist. Wenn Sie eine E-Mail erwarten, prüfen Sie das Format. Alles andere lehnen Sie ab.
\n\nFehler Nr. 4: Ignorieren des Ausgabekontexts (XSS)
\n\nSie haben die Daten mit Prepared Statements in der Datenbank gespeichert. Super, keine SQL-Injection mehr. Aber jetzt geben Sie die Daten in HTML aus, ohne sie zu escapen. Das ist, als würden Sie die Haustür abschließen, aber alle Fenster offen lassen.
\n\nBeispiel für eine XSS-Schwachstelle:
\n\n<?php\n// Daten aus der DB holen\n$comment = $row['comment'];\n// Direkt ausgeben – gefährlich!\necho \"<p>$comment</p>\";\n// Wenn $comment <script>alert('XSS')</script> ist, wird das Skript ausgeführt\n?>\n\nSo sollte es sein: Verwenden Sie htmlspecialchars() mit dem richtigen Encoding für den HTML-Kontext:
<?php\necho \"<p>\" . htmlspecialchars($comment, ENT_QUOTES, 'UTF-8') . \"</p>\";\n// <script> wird zu <script> – harmlos\n?>\n\nDenken Sie daran: Escapen Sie bei der Ausgabe, nicht bei der Eingabe. So bleiben Ihre Daten in der Datenbank sauber und werden erst im richtigen Kontext sicher gemacht.
\n\nFehler Nr. 5: Keine serverseitige Validierung (nur clientseitig)
\n\nClientseitige Validierung mit JavaScript ist großartig für die Benutzerfreundlichkeit, aber sie ist kein Sicherheitsmechanismus. Ein Angreifer kann Ihre JavaScript-Validierung einfach umgehen, indem er die Anfrage direkt an Ihren Server sendet (z. B. mit curl oder Postman).
\n\nSo sollte es sein: Führen Sie immer eine serverseitige Validierung durch. Die clientseitige Validierung ist nur ein Komfort-Feature, kein Sicherheitsfeature.
\n\n<?php\n// Serverseitige Validierung ist ein MUSS\nif (empty($_POST['name']) || strlen($_POST['name']) > 100) {\n echo \"Ungültiger Name\";\n exit;\n}\n// Jetzt erst die Daten verarbeiten\n?>\n\nFazit: Sicherheit ist kein Feature, sondern ein Prozess
\n\nDie Bereinigung von Benutzereingaben in PHP ist kein einmaliger Schritt, sondern ein kontinuierlicher Prozess. Hier sind die wichtigsten Takeaways:
\n\n- \n
- Verwenden Sie Prepared Statements für alle Datenbankabfragen (PDO oder MySQLi). \n
- Validieren Sie Eingaben (prüfen Sie das Format) und lehnen Sie ungültige Daten ab. \n
- Escapen Sie Ausgaben mit
htmlspecialchars()im richtigen Kontext. \n - Vertrauen Sie niemals auf clientseitige Validierung allein. \n
- Vergessen Sie veraltete Funktionen wie
mysql_real_escape_string()undaddslashes(). \n
Wenn Sie diese Prinzipien befolgen, sind Sie auf dem besten Weg, sichere PHP-Anwendungen zu schreiben. Und denken Sie daran: Sicherheit ist kein Ziel, sondern eine Reise. Bleiben Sie neugierig und aktualisieren Sie Ihr Wissen regelmäßig!