Wissen › Cross-Site Scripting (XSS)
Cross-Site Scripting (XSS)
Fremder Code läuft im Browser anderer Nutzer — weil Ausgaben nicht kontextgerecht kodiert werden.
Cross-Site Scripting entsteht, wenn eine Anwendung Daten in eine Seite schreibt, ohne sie für den jeweiligen Ausgabekontext (HTML, Attribut, JavaScript, URL) zu kodieren. Angreifer schleusen so aktiven Code ein, der im Browser anderer Besucher ausgeführt wird — inklusive eingeloggter Redakteure und Administratoren.
Wie der Angriff funktioniert
- Eingabe gelangt ungefiltert in die Ausgabe: ein Wert aus Formular, URL, Cookie oder Datenbank wird roh ins HTML geschrieben.
- Der Browser kann nicht zwischen gewolltem Markup und eingeschleustem Code unterscheiden — ein <script>, ein Event-Handler (onerror, onload) oder ein ausbrechendes "> wird aktiv.
- Der Code läuft mit den Rechten des Opfers: er kann Aktionen im Namen des Nutzers auslösen, Tokens abgreifen oder weitere Angriffe nachladen.
Varianten
Beispiel
Wird ein Nutzerwert ohne Kodierung ausgegeben, bleibt eingeschleustes Markup aktiv:
<!-- unsicher: roh ausgegeben -->
<div class="comment"><?= $comment ?></div>
<!-- sicher: kontextgerecht kodiert -->
<div class="comment"><?= htmlspecialchars($comment, ENT_QUOTES) ?></div>
Mögliche Auswirkungen
- Übernahme von Sitzungen / Aktionen im Namen des Opfers (auch im Backend).
- Diebstahl von CSRF-Tokens, Daten-Exfiltration, Phishing innerhalb der vertrauten Domain.
- Bei Treffern auf Admin-Sessions: faktische Übernahme der Redaktion/Installation.
Worauf du in TYPO3 achten musst
TYPO3 ist hier gut aufgestellt — solange man die Standardmechanismen nicht aushebelt. Fluid kodiert HTML-Ausgaben standardmäßig automatisch. Die meisten XSS-Lücken in TYPO3-Projekten entstehen genau dort, wo dieses Escaping bewusst abgeschaltet wird.
Fluid escaped automatisch — verlasse dich darauf
{variable} in einem Fluid-Template wird automatisch HTML-kodiert. Für normale Textausgabe ist nichts weiter nötig. Der Fehler ist fast immer das bewusste Abschalten.
f:format.raw / |raw ist der Hauptverdächtige
<f:format.raw>{userInput}</f:format.raw> bzw. {userInput -> f:format.raw()} gibt den Wert UNkodiert aus. Nur auf vertrauenswürdige, bereits bereinigte Inhalte anwenden — nie auf Nutzereingaben.
<!-- gefährlich bei Nutzereingabe -->
<f:format.raw>{comment.message}</f:format.raw>
<!-- sicher: Standardausgabe (escaped) -->
{comment.message} RTE-/HTML-Inhalte sanitizen, nicht roh ausgeben
Richtext-Felder dürfen HTML enthalten. Gib sie über f:format.html (parseFunc, serverseitig gefiltert) aus — nicht über f:format.raw. Für freie HTML-Eingaben eine Allowlist-Bereinigung (HTML-Sanitizer) einsetzen.
Backend/TCA: Eingaben am Rand prüfen
TCA-'eval' (z. B. trim, int, alphanum_x) begrenzt, was gespeichert wird. Das ersetzt aber kein Ausgabe-Escaping — XSS entsteht bei der Ausgabe, nicht bei der Eingabe.
GeneralUtility::_GP & Co. nie roh ins HTML
Request-Werte (GET/POST) immer über htmlspecialchars() bzw. Fluid kodieren, bevor sie ausgegeben werden — besonders in eigenen ViewHelpern und PHP-gerenderten Snippets.
Content-Security-Policy als zweite Verteidigungslinie
TYPO3 v11 bringt eine CSP-Unterstützung (Frontend/Backend) mit; ab v12 ausgebaut. Eine strikte CSP reduziert den Schaden, ersetzt aber korrektes Escaping nicht.
Schutzmaßnahmen
- Ausgaben immer kontextgerecht kodieren (HTML, Attribut, JS, URL) — in Fluid die Standardausgabe nutzen.
- f:format.raw nur auf vertrauenswürdige Inhalte; RTE-HTML über f:format.html bzw. einen Sanitizer.
- Content-Security-Policy, httpOnly-Cookies und SameSite als Defense-in-depth.
Interaktiv üben
In der Lernplattform kannst du diese Schwachstellenklasse an einer echten, isolierten TYPO3-Instanz nachvollziehen: