Aktuelle Lage: PHP2Shell. Zwei kritische PHP-Lücken (CVSS 9.2) erlauben Schadcode ohne Anmeldung. Patches seit 21.10.2026.Was jetzt zu tun ist →

XSS in PHP verhindern: Cross-Site-Scripting sicher abwehren

Wie Entwickler Cross-Site-Scripting in PHP-Anwendungen verhindern: kontextgerechte Kodierung, Auto-Escaping in Templates, Bereinigung von HTML und eine Content Security Policy.

Stand 5 Min. LesezeitRatgeber

Kurz gesagt: XSS in PHP verhindern Sie, indem Sie jede Ausgabe passend zu ihrem Kontext kodieren: htmlspecialchars() für HTML, json_encode() mit Schutzoptionen für JavaScript, geprüfte URLs für Links. Templates mit automatischem Escaping nehmen Ihnen viel davon ab. Eine Content Security Policy und HttpOnly-Cookies begrenzen den Schaden, falls doch eine Lücke bleibt.

Warum Cross-Site-Scripting jetzt mitgeprüft werden sollte

Die Aufmerksamkeit liegt im Oktober 2026 auf PHP2Shell, zwei kritischen Lücken im PHP-Interpreter, für die seit dem 21.10.2026 Patches vorliegen. Viele Unternehmen lassen ihre Webanwendungen in diesem Zuge überprüfen. Das ist ein guter Anlass, auch Schwachstellen im eigenen Code anzusehen, die kein PHP-Update behebt.

Cross-Site-Scripting, kurz XSS, ist eine davon. Die OWASP Top 10 führen XSS innerhalb der Kategorie Injection. Anders als bei einer Lücke im Server richtet sich der Angriff hier gegen die Besucher und Nutzer Ihrer Website, etwa gegen Kunden im Shop oder Mitarbeitende im Backend.

Die Folgen können erheblich sein: übernommene Sitzungen von Administratoren, manipulierte Formulare, die Daten an Dritte senden, oder gefälschte Inhalte auf Ihrer Website. Wird ein Administratorkonto übernommen, kann das bis zur vollständigen Kontrolle über die Anwendung führen.

Wie entsteht XSS in PHP-Anwendungen?

XSS entsteht, wenn eine Anwendung Daten aus einer nicht vertrauenswürdigen Quelle ungeprüft in eine Seite ausgibt. Der Browser kann dann nicht mehr zwischen Ihren Inhalten und eingeschleustem Code unterscheiden und führt beides aus.

Man unterscheidet drei Formen. Bei reflektiertem XSS stammt der Inhalt direkt aus der aktuellen Anfrage, etwa aus einem Suchbegriff in der URL. Bei gespeichertem XSS liegt er in der Datenbank, zum Beispiel in einem Kommentar oder Profilfeld, und trifft jeden, der die Seite aufruft. DOM-basiertes XSS entsteht im JavaScript des Browsers, wenn Skripte Werte aus der URL in die Seite schreiben.

Nicht vertrauenswürdig sind alle Daten, die nicht fest im Code stehen: Formularfelder, URL-Parameter, Cookies, Dateinamen, Antworten externer Schnittstellen und Inhalte aus der eigenen Datenbank, die irgendwann von außen kamen.

Ausgabe je Kontext richtig kodieren

Die wichtigste Regel lautet: Kodieren bei der Ausgabe, und zwar passend zum Ort, an dem der Wert landet. Für HTML-Inhalt und Attribute in Anführungszeichen ist htmlspecialchars() das Mittel der Wahl. Eine kleine Hilfsfunktion verhindert, dass Optionen vergessen werden:

<?php
function e(?string $wert): string
{
    return htmlspecialchars($wert ?? '', ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8');
}
?>
<h2><?= e($produkt['name']) ?></h2>
<input type="text" name="suche" value="<?= e($_GET['q'] ?? '') ?>">

Andere Kontexte brauchen andere Mittel:

Kontext Sichere Methode
HTML-Inhalt, Attribut in Anführungszeichen htmlspecialchars() mit ENT_QUOTES und UTF-8
Daten für JavaScript json_encode() mit JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_HEX_QUOT
Parameter in einer URL rawurlencode() für den einzelnen Wert
Vollständige URL aus Benutzereingabe Schema prüfen, nur https und http zulassen, dann htmlspecialchars()
Attribute ohne Anführungszeichen, Event-Handler, CSS vermeiden, Werte dort nicht einsetzen

Für Daten, die ein Skript braucht, ist ein Datenattribut oder ein JSON-Block meist der sauberste Weg:

<?php
$daten = json_encode($konfiguration, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
?>
<div id="app" data-konfig="<?= e($daten) ?>"></div>

Im JavaScript lesen Sie den Wert dann über das Datenattribut aus und setzen Inhalte mit textContent statt mit innerHTML.

Templates, HTML-Bereinigung und Frameworks

Template-Engines wie Twig und Blade kodieren Ausgaben standardmäßig automatisch. Das schließt einen Großteil typischer Fehler aus. Gefährlich wird es dort, wo dieses Verhalten bewusst abgeschaltet wird, etwa mit dem Filter raw in Twig oder der Syntax {!! !!} in Blade. Solche Stellen sollten im Code selten sein und bei jedem Review gezielt geprüft werden.

Soll Ihre Anwendung bewusst HTML von Nutzern zulassen, etwa Formatierungen in Kommentaren oder in einem Redaktionssystem, reicht Kodieren nicht, weil das HTML ja dargestellt werden soll. Dann brauchen Sie eine geprüfte Bereinigungsbibliothek wie HTML Purifier, die nur eine feste Liste erlaubter Elemente und Attribute durchlässt. Eigene Filter mit regulären Ausdrücken sind erfahrungsgemäß lückenhaft.

Wichtig

Prüfen Sie besonders Backend-Bereiche. XSS in Ansichten, die nur Administratoren sehen, wird oft unterschätzt, trifft aber genau die Konten mit den meisten Rechten.

XSS in PHP-Bestandscode finden

In gewachsenen Anwendungen ist die erste Frage meist nicht, wie man richtig kodiert, sondern wo es bisher vergessen wurde. Ein pragmatischer Einstieg ist die Suche nach Stellen, an denen Variablen direkt ausgegeben werden:

# Direkte Ausgaben von Anfragedaten
grep -rnE "(echo|print|<\?=)\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" src/ templates/ --include="*.php"
# Abgeschaltetes Auto-Escaping in Twig und Blade
grep -rnE "\|raw|\{!!" templates/ resources/views/

Treffer sind Prüfaufträge, keine fertigen Befunde. Gespeichertes XSS findet eine solche Suche nur bedingt, weil die Werte dort aus der Datenbank kommen. Prüfen Sie deshalb zusätzlich alle Ansichten, die Inhalte von Nutzern anzeigen: Kommentare, Profile, Bestellnotizen, Support-Tickets. Bei CMS und Shops gehören Plugins und Themes von Drittanbietern ausdrücklich dazu, denn dort sitzt ein großer Teil der Ausgabelogik.

Zweite Verteidigungslinie: CSP und sichere Cookies

Auch bei sorgfältigem Code kann eine Stelle übersehen werden. Zwei Maßnahmen begrenzen dann den Schaden. Eine Content Security Policy erlaubt dem Browser nur Skripte aus festgelegten Quellen und verbietet eingebettete Skripte, sofern sie nicht ausdrücklich freigegeben sind:

Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"

Führen Sie eine solche Richtlinie schrittweise ein, zunächst im reinen Berichtsmodus über Content-Security-Policy-Report-Only, denn bestehende Einbindungen von Analyse- oder Zahlungsdiensten müssen meist ergänzt werden. Weitere Header beschreibt der Ratgeber Sicherheits-Header für Websites.

Zusätzlich sollten Sitzungscookies das Attribut HttpOnly tragen, damit Skripte sie nicht auslesen können. Wie Sie Sessions insgesamt absichern, steht im Ratgeber Sessions in PHP absichern. Eine verwandte Schwachstelle auf der Datenbankseite behandelt SQL-Injection in PHP verhindern.

Wie hilft PHP SOS konkret?

  • Wir prüfen Templates und Ausgaben Ihrer Anwendung auf fehlende oder falsche Kodierung.
  • Wir bewerten Funde nach Erreichbarkeit und betroffenen Konten und zeigen konkrete Korrekturen.
  • Wir führen eine Content Security Policy schrittweise ein, ohne Shop- oder Zahlungsfunktionen zu stören.
  • Wir testen nach der Korrektur erneut und dokumentieren das Ergebnis.

Eine unabhängige Prüfung beschreibt die Leistung Sicherheitsaudit und Penetrationstest.

Häufige Fragen

Reicht htmlspecialchars gegen XSS?

Für normalen Text im HTML-Inhalt und in Attributen in Anführungszeichen ja, wenn Sie ENT_QUOTES und den Zeichensatz UTF-8 angeben. In JavaScript, in URLs oder in CSS gelten andere Regeln, dort braucht es eine eigene, passende Kodierung.

Sollte ich Eingaben beim Speichern oder bei der Ausgabe filtern?

Kodieren Sie bei der Ausgabe, passend zum Ziel. Eingaben sollten Sie beim Empfang auf Plausibilität prüfen, etwa Länge und Format. Wer nur beim Speichern filtert, übersieht Daten aus anderen Quellen und erschwert spätere Nutzung in anderen Kontexten.

Was bringt eine Content Security Policy?

Eine Content Security Policy legt fest, aus welchen Quellen der Browser Skripte laden und ausführen darf. Sie kann die Auswirkungen einer übersehenen XSS-Lücke deutlich begrenzen, ersetzt aber keine korrekte Kodierung.

Wie erlaube ich Formatierungen wie fett oder Links in Kommentaren?

Nutzen Sie eine geprüfte HTML-Bereinigungsbibliothek mit einer Whitelist erlaubter Elemente und Attribute. Eigene reguläre Ausdrücke zum Entfernen von Skripten sind fehleranfällig und sollten nicht verwendet werden.

Quellen

Sofort-Kontakt

Jede Stunde zählt. Schreiben Sie uns jetzt.

Schildern Sie kurz System, PHP-Version und Beobachtung. Wir melden uns, klären die Lage und arbeiten remote, bis der Vorfall abgeschlossen und dokumentiert ist.

Sofort-Hilfe