XSS verhindern in PHP – Ausgaben richtig escapen mit htmlspecialchars
SQL-Injection verhinderst du mit Prepared Statements – aber der andere große Angriff, XSS, passiert bei der AUSGABE. Ich zeige dir, warum du jede dynamische Ausgabe mit htmlspecialchars und ENT_QUOTES escapen musst und wie ein kurzer Helfer das übernimmt.
Prepared Statements schützen deine Datenbank vor SQL-Injection. Der zweite große Angriff, Cross-Site-Scripting (XSS), passiert an einer ganz anderen Stelle: bei der Ausgabe. Gibst du Nutzertext ungeprüft ins HTML, kann jemand <script>-Code einschleusen, der im Browser deiner Besucher läuft.
Das Problem
// Ein Besucher trägt als Namen ein: <script>stehleCookie()</script>
echo "Hallo " . $_GET['name']; // 💥 der Code wird im Browser ausgeführtDie Lösung: escapen bei der Ausgabe
echo "Hallo " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
// Ausgabe: Hallo <script>stehleCookie()</script>htmlspecialchars wandelt <, >, & und Anführungszeichen in harmlose HTML-Entities um. Der Text erscheint dann exakt so, wie er eingegeben wurde – aber der Browser führt ihn nicht mehr als Code aus.
Wichtig ist das zweite Argument ENT_QUOTES. Ohne es bleiben einfache Anführungszeichen ' stehen – und wenn du Nutzertext in ein Attribut schreibst (value='...'), kann jemand daraus ausbrechen. ENT_QUOTES escapt beide Anführungszeichen-Arten.
Ein kurzer Helfer, den du überall nutzt
function h(string $s): string
{
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
?>
<h1><?= h($titel) ?></h1>
<input value="<?= h($eingabe) ?>">Die Regel dahinter ist simpel: Escape so spät wie möglich – direkt bei der Ausgabe, nicht beim Speichern. So bleibt in der Datenbank der Originaltext, und du entscheidest je Kontext (HTML, Attribut, URL), wie escaped wird.
Genau diesen h()-Helfer nutze ich in jeder PHP-Seite, die ich baue. Brauchst du eine sichere Website? Melde dich über bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Beträge und Zahlen in PHP formatieren – number_format, sprintf und Intl
1234.5 ist keine Anzeige, sondern ein Wert. Auf der Rechnung soll 1.234,50 € stehen, in der API 1234.50 und im Dateinamen 1234-50. Drei Aufgaben, drei Werkzeuge – und ein Fehler, den fast jeder einmal macht.
Benannte Argumente in PHP 8 – Schluss mit true, false, null, true
Ein Aufruf wie erstelle($a, true, false, null, true) sagt nichts darüber, was die Wahrheitswerte bedeuten. Mit benannten Argumenten steht es im Aufruf – und optionale Parameter lassen sich überspringen.
Reguläre Ausdrücke in PHP – benannte Gruppen statt $m[3]
Ein Treffer-Array aus Zahlen liest sich nach zwei Wochen wie eine Geheimschrift. Benannte Gruppen geben jedem Teil einen Namen – und preg_replace_callback ersetzt damit Dinge, die kein einfacher Ersetzungsstring kann.