Latte ist ein Synonym für Sicherheit
Latte ist das einzige Templating-System für PHP mit wirksamem Schutz vor der kritischen Sicherheitslücke Cross-site Scripting (XSS). Möglich macht das kontextsensitives Escaping. Wir besprechen:
- das Prinzip der Sicherheitslücke XSS und warum sie so gefährlich ist
- was Latte bei der Abwehr von XSS so wirksam macht
- wie in Twig, Blade und ähnlichen Templates leicht Sicherheitslücken entstehen
Cross-site Scripting (XSS)
Cross-site Scripting (kurz XSS) ist eine der häufigsten und gefährlichsten Sicherheitslücken von Websites. Sie erlaubt es einem Angreifer, ein schädliches Skript (Malware) in eine fremde Seite einzuschleusen, das dann im Browser eines ahnungslosen Benutzers läuft.
Was kann ein solches Skript anrichten? Es kann zum Beispiel beliebige Inhalte der kompromittierten Seite an den Angreifer senden, einschließlich sensibler Daten, die nach dem Anmelden angezeigt werden. Es kann die Seite verändern oder im Namen des Benutzers andere Requests ausführen. Handelte es sich etwa um ein Webmail, könnte es sensible Nachrichten lesen, die angezeigten Inhalte verändern oder Einstellungen ändern – zum Beispiel die Weiterleitung von Kopien aller Nachrichten an die Adresse des Angreifers aktivieren, um Zugriff auf künftige E-Mails zu bekommen.
Deshalb gehört XSS beständig zu den gefährlichsten Sicherheitslücken. Taucht sie auf einer Website auf, muss sie so schnell wie möglich beseitigt werden, damit sie nicht ausgenutzt wird.
Wie entsteht die Sicherheitslücke?
Der Fehler entsteht dort, wo die Webseite erzeugt und Variablen ausgegeben werden. Stellen Sie sich vor, Sie erstellen eine Suchseite, an deren Anfang ein Absatz mit dem gesuchten Begriff steht:
echo '<p>Search results for <em>' . $search . '</em></p>';
Ein Angreifer kann in das Suchfeld und damit in die Variable $search eine beliebige Zeichenfolge eingeben, auch
HTML-Code wie <script>alert("Hacked!")</script>. Da die Ausgabe nicht bereinigt wird, wird sie Teil der
angezeigten Seite:
<p>Search results for <em><script>alert("Hacked!")</script></em></p>
Statt den gesuchten Text anzuzeigen, führt der Browser das JavaScript aus. Und damit übernimmt der Angreifer die Kontrolle über die Seite.
Sie könnten einwenden, dass das Einfügen von Code in eine Variable das JavaScript ausführt, aber nur im Browser des Angreifers. Wie gelangt es zum Opfer? Aus dieser Sicht unterscheiden wir mehrere Arten von XSS. In unserem Suchbeispiel sprechen wir von reflektiertem XSS. Dabei muss das Opfer dazu gebracht werden, einen Link anzuklicken, der den schädlichen Code in einem Parameter enthält:
https://example.com/?search=<script>alert("Hacked!")</script>
Den Benutzer zum Klick auf den Link zu bringen erfordert etwas Social Engineering, ist aber nicht übermäßig kompliziert.
Benutzer klicken auf Links, ob in E-Mails oder in sozialen Netzwerken, ohne groß nachzudenken. Dass die Adresse etwas
Verdächtiges enthält, lässt sich mit einem URL-Verkürzer verschleiern; der Benutzer sieht dann nur
bit.ly/xxx.
Es gibt jedoch eine zweite, weit gefährlichere Form des Angriffs, bekannt als gespeichertes XSS oder persistentes XSS, bei der es dem Angreifer gelingt, schädlichen Code auf dem Server zu speichern, sodass er automatisch in bestimmte Seiten eingefügt wird.
Ein Beispiel sind Seiten, auf denen Benutzer Kommentare schreiben. Ein Angreifer sendet einen Beitrag ab, der Code enthält, und dieser wird auf dem Server gespeichert. Sind die Seiten nicht ausreichend abgesichert, läuft der Code anschließend im Browser jedes Besuchers.
Es könnte scheinen, der Kern des Angriffs bestehe darin, die Zeichenfolge <script> in die Seite zu
bekommen. In Wirklichkeit gibt es
viele Wege, JavaScript einzufügen. Zeigen wir ein Beispiel mit einem HTML-Attribut. Denken Sie an eine Fotogalerie, in der
sich zu Bildern Beschriftungen hinzufügen lassen, die im Attribut alt angezeigt werden:
echo '<img src="' . $imageFile . '" alt="' . $imageAlt . '">';
Ein Angreifer muss als Beschriftung nur die geschickt gebaute Zeichenfolge " onload="alert('Hacked!') einfügen,
und wenn die Ausgabe nicht bereinigt wird, sieht der entstehende Code so aus:
<img src="photo0145.webp" alt="" onload="alert('Hacked!')">
Das eingeschleuste Attribut onload wird nun Teil der Seite. Der Browser führt den darin enthaltenen Code aus,
sobald das Bild geladen ist. Gehackt!
Wie wehrt man sich gegen XSS?
Jeder Versuch, Angriffe mit Blacklists zu erkennen, etwa durch Sperren der Zeichenfolge <script>, ist
unzureichend. Grundlage einer funktionierenden Abwehr ist die konsequente Bereinigung aller Daten, die innerhalb der Seite
ausgegeben werden.
In erster Linie geht es darum, alle Zeichen mit besonderer Bedeutung durch die entsprechenden Sequenzen zu ersetzen,
umgangssprachlich Escaping genannt (das erste Zeichen der Sequenz heißt Escape-Zeichen, daher der Name). Im HTML-Text hat
zum Beispiel das Zeichen < eine besondere Bedeutung; soll es nicht als Beginn eines Tags interpretiert werden,
müssen wir es durch eine optisch entsprechende Sequenz ersetzen, die HTML-Entity <. Der Browser zeigt dann
das Kleiner-als-Zeichen an.
Entscheidend ist, den Kontext zu unterscheiden, in dem die Daten ausgegeben werden. Denn Strings werden in verschiedenen Kontexten unterschiedlich bereinigt. In verschiedenen Kontexten haben verschiedene Zeichen eine besondere Bedeutung. Das Escaping unterscheidet sich zum Beispiel im HTML-Text, in HTML-Attributen, innerhalb bestimmter besonderer Elemente usw. Darauf gehen wir gleich ausführlich ein.
Die Bereinigung erfolgt am besten genau in dem Moment, in dem der String auf der Seite ausgegeben wird – so ist sichergestellt, dass sie tatsächlich und genau einmal stattfindet. Am besten ist es, wenn sich das Templating-System automatisch darum kümmert. Denn wenn die Bereinigung nicht automatisch geschieht, kann der Programmierer sie vergessen. Und ein einziges Versehen bedeutet, dass die Website verwundbar ist.
XSS betrifft jedoch nicht nur das Ausgeben von Daten in Templates, sondern auch andere Teile der Anwendung, die mit nicht
vertrauenswürdigen Daten korrekt umgehen müssen. So muss zum Beispiel JavaScript in Ihrer Anwendung im Zusammenhang mit nicht
vertrauenswürdigen Daten innerText oder textContent verwenden, nicht innerHTML. Besondere
Aufmerksamkeit verdienen Funktionen, die Strings als JavaScript auswerten, etwa eval(), aber auch
setTimeout(), oder die Verwendung von setAttribute() mit Event-Attributen wie onload usw.
Das geht jedoch über den Bereich hinaus, den Templates abdecken.
Die ideale Abwehr in 3 Punkten:
- Sie erkennt den Kontext, in dem die Daten ausgegeben werden.
- Sie bereinigt die Daten gemäß den Regeln dieses Kontexts (also „kontextsensitiv“).
- Sie tut das automatisch.
Kontextsensitives Escaping
Was genau ist mit dem Wort Kontext gemeint? Es ist eine Stelle im Dokument mit eigenen Regeln für den Umgang mit den ausgegebenen Daten. Sie hängt vom Dokumenttyp ab (HTML, XML, CSS, JavaScript, reiner Text, …) und kann sich in einzelnen Teilen unterscheiden. In einem HTML-Dokument gibt es zum Beispiel viele Stellen (Kontexte), an denen sehr unterschiedliche Regeln gelten. Sie werden überrascht sein, wie viele es sind. Hier die ersten vier:
<p>#text</p>
<img src="#attribute">
<textarea>#rawtext</textarea>
<!-- #comment -->
Der standardmäßige und grundlegende Kontext einer HTML-Seite ist HTML-Text. Welche Regeln gelten hier? Die Zeichen
< und & haben eine besondere Bedeutung, sie stehen für den Beginn eines Tags oder einer Entity,
wir müssen sie also escapen, indem wir sie durch HTML-Entities ersetzen (< wird zu <,
& wird zu &).
Der zweithäufigste Kontext ist der Wert eines HTML-Attributs. Er unterscheidet sich vom Text darin, dass hier das
Anführungszeichen " oder ', das das Attribut begrenzt, eine besondere Bedeutung hat. Es muss als Entity
geschrieben werden, damit es nicht als Ende des Attributs interpretiert wird. Umgekehrt lässt sich das Zeichen <
innerhalb eines Attributs gefahrlos verwenden, weil es dort keine besondere Bedeutung hat; es kann nicht als Beginn eines Tags
oder Kommentars interpretiert werden. Aber Achtung: In HTML lassen sich Attributwerte auch ohne Anführungszeichen schreiben, und
dann hat eine ganze Reihe von Zeichen eine besondere Bedeutung, womit ein weiterer eigener Kontext entsteht.
Sie werden überrascht sein, aber innerhalb der Elemente <textarea> und <title> gelten
besondere Regeln: Dort muss das Zeichen < nicht escapt werden (kann es aber), sofern ihm kein /
folgt. Das ist aber eher eine Kleinigkeit.
Interessant wird es innerhalb von HTML-Kommentaren. Hier werden zum Escapen keine HTML-Entities verwendet. Tatsächlich sagt keine Spezifikation, wie in Kommentaren zu escapen ist. Sie müssen lediglich einige kuriose Regeln einhalten und bestimmte Zeichenkombinationen darin vermeiden.
Kontexte können sich auch schichten, was geschieht, wenn wir JavaScript oder CSS in HTML einbetten. Das lässt sich auf zwei verschiedene Arten tun, über ein Element oder ein Attribut:
<script>#js-element</script>
<img onclick="#js-attribute">
<style>#css-element</style>
<p style="#css-attribute"></p>
Zwei Wege und zwei verschiedene Arten, Daten zu escapen. Innerhalb der Elemente <script> und
<style> wird, genau wie bei HTML-Kommentaren, kein Escaping mit HTML-Entities durchgeführt. Beim Ausgeben von
Daten innerhalb dieser Elemente ist nur eine Regel einzuhalten: Der Text darf nicht die Sequenz </script bzw.
</style enthalten.
Umgekehrt wird in den Attributen style und on*** mit HTML-Entities escapt.
Und innerhalb des eingebetteten JavaScript oder CSS gelten natürlich die Escaping-Regeln dieser Sprachen. Ein String in einem
Attribut wie onload wird also zuerst nach den Regeln von JS und dann nach den Regeln für HTML-Attribute escapt.
Puh … Wie Sie sehen, ist HTML ein sehr komplexes Dokument, in dem sich Kontexte schichten, und ohne genau zu wissen, wo Sie Daten ausgeben (also in welchem Kontext), lässt sich nicht sagen, wie es richtig geht.
Wollen Sie ein Beispiel?
Nehmen wir den String Rock'n'Roll.
Geben Sie ihn im HTML-Text aus, ist in diesem konkreten Fall keine Ersetzung nötig, weil der String keine Zeichen mit besonderer Bedeutung enthält. Anders liegt der Fall, wenn Sie ihn innerhalb eines HTML-Attributs ausgeben, das in einfache Anführungszeichen gefasst ist. Dann müssen Sie die Anführungszeichen in HTML-Entities escapen:
<div title='Rock'n'Roll'></div>
Das war einfach. Eine weit interessantere Situation entsteht, wenn sich Kontexte schichten, etwa wenn der String Teil von JavaScript ist.
Geben wir ihn zunächst innerhalb des JavaScript selbst aus. Wir fassen ihn also in Anführungszeichen und escapen zugleich die
darin enthaltenen Anführungszeichen mit dem Zeichen \:
'Rock\'n\'Roll'
Wir können auch einen Funktionsaufruf ergänzen, damit der Code etwas tut:
alert('Rock\'n\'Roll');
Fügen wir diesen Code mit <script> in ein HTML-Dokument ein, ist keine weitere Anpassung nötig, weil er
die verbotene Sequenz </script nicht enthält:
<script> alert('Rock\'n\'Roll'); </script>
Wollten wir ihn jedoch in ein HTML-Attribut einfügen, müssen wir die Anführungszeichen weiterhin in HTML-Entities escapen:
<div onclick='alert('Rock\'n\'Roll')'></div>
Der eingebettete Kontext muss aber nicht nur JS oder CSS sein. Häufig ist es auch eine URL. Parameter in URLs werden escapt,
indem Zeichen mit besonderer Bedeutung in Sequenzen umgewandelt werden, die mit % beginnen. Beispiel:
https://example.org/?a=Jazz&b=Rock%27n%27Roll
Und wenn wir diesen String in einem Attribut ausgeben, wenden wir zusätzlich das Escaping dieses Kontexts an und ersetzen
& durch &:
<a href="https://example.org/?a=Jazz&b=Rock%27n%27Roll">
Wenn Sie bis hierher gelesen haben: Glückwunsch, das war anstrengend. Nun haben Sie ein gutes Verständnis davon, was Kontexte und Escaping sind. Und Sie müssen sich keine Sorgen machen, dass es kompliziert wäre. Latte erledigt das automatisch für Sie.
Latte vs. naive Systeme
Wir haben gezeigt, wie man in einem HTML-Dokument richtig escapt und wie entscheidend das Wissen um den Kontext ist, also um die Stelle, an der wir Daten ausgeben. Mit anderen Worten: wie kontextsensitives Escaping funktioniert. Obwohl das eine notwendige Voraussetzung für eine funktionierende Abwehr von XSS ist, beherrscht es Latte als einziges Templating-System für PHP.
Wie ist das möglich, wo doch heute alle Systeme behaupten, automatisches Escaping zu haben? Automatisches Escaping ohne Kenntnis des Kontexts ist ein Trugschluss, der ein falsches Gefühl von Sicherheit erzeugt.
Templating-Systeme wie Twig, Laravel Blade und andere sehen im Template keinerlei HTML-Struktur. Sie sehen daher auch keine Kontexte. Verglichen mit Latte sind sie blind und naiv. Sie verarbeiten nur ihre eigenen Tags; alles andere ist für sie ein bedeutungsloser Strom von Zeichen:
░░░░░░░░░░░░░░░░░{{ foo }}░░░░░░░
░░░░░░░░░░░░░░░░{{ foo }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ foo }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ foo }}░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ foo }}░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ foo }}░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ foo }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ foo }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ foo }}░░░░░░░░░░░
░░░░░░░░░░░░░░░░░░░{{ foo }}░░░░
- im Text: <span>{{ foo }}</span>
- im Tag: <span {{ foo }} ></span>
- im Attribut: <span title='{{ foo }}'></span>
- im Attribut ohne Anführungszeichen: <span title={{ foo }}></span>
- im Attribut mit einer URL: <a href="{{ foo }}"></a>
- im Attribut mit JavaScript: <img onload="{{ foo }}">
- im Attribut mit CSS: <span style="{{ foo }}"></span>
- in JavaScript: <script>var = {{ foo }}</script>
- in CSS: <style>body { content: {{ foo }}; }</style>
- im Kommentar: <!-- {{ foo }} -->
Naive Systeme wandeln lediglich mechanisch die Zeichen < > & ' " in HTML-Entities um, was zwar in den
meisten Anwendungsfällen eine gültige Art des Escapings ist, aber bei weitem nicht immer genügt. Sie können daher die
Entstehung verschiedener Sicherheitslücken weder erkennen noch verhindern, wie wir gleich zeigen.
Latte sieht das Template genauso wie Sie. Es versteht HTML und XML, erkennt Tags, Attribute usw. Und dadurch unterscheidet es die einzelnen Kontexte und behandelt die Daten entsprechend. Es bietet damit einen wirklich wirksamen Schutz vor der kritischen Sicherheitslücke Cross-site Scripting.
░░░░░░░░░░░<span>{$foo}</span>
░░░░░░░░░░<span {$foo} ></span>
░░░░░░░░░░░░░░░░<span title='{$foo}'></span>
░░░░░░░░░░░░░░░░░░░░░░░░░<span title={$foo}></span>
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░<a href="{$foo}"></a>
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░<img onload="{$foo}">
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░<span style="{$foo}"></span>
░░░░░░░░░░░░░░░░░░<script>░░░░░░{$foo}</script>
░░░░░░░░░░<style>░░░░░░░░░░░░░░░░{$foo}░░░</style>
░░░░░░░░░░░░░░<!--░{$foo}░-->
- im Text: <span>{$foo}</span>
- im Tag: <span {$foo} ></span>
- im Attribut: <span title='{$foo}'></span>
- im Attribut ohne Anführungszeichen: <span title={$foo}></span>
- im Attribut mit einer URL: <a href="{$foo}"></a>
- im Attribut mit JavaScript: <img onload="{$foo}">
- im Attribut mit CSS: <span style="{$foo}"></span>
- in JavaScript: <script>var = {$foo}</script>
- in CSS: <style>body { content: {$foo}; }</style>
- im Kommentar: <!-- {$foo} -->
Live-Demonstration
Links sehen Sie das Template in Latte, rechts den erzeugten HTML-Code. Die Variable $text wird mehrfach
ausgegeben, jedes Mal in einem etwas anderen Kontext. Und daher jedes Mal etwas anders escapt. Sie können den Code des Templates
selbst bearbeiten, zum Beispiel den Inhalt der Variablen ändern usw. Probieren Sie es aus:
Ist das nicht großartig! Latte führt kontextsensitives Escaping automatisch durch, sodass der Programmierer:
- nicht darüber nachdenken oder wissen muss, wo wie zu escapen ist
- keinen Fehler machen kann
- das Escaping nicht vergessen kann
Und das sind noch nicht einmal alle Kontexte, die Latte beim Ausgeben unterscheidet und für die es den Umgang mit den Daten anpasst. Gehen wir nun weitere interessante Fälle durch.
Wie man naive Systeme hackt
An mehreren praktischen Beispielen zeigen wir, wie wichtig die Unterscheidung der Kontexte ist und warum naive Templating-Systeme anders als Latte keinen ausreichenden Schutz vor XSS bieten. In den Beispielen verwenden wir Twig als Vertreter eines naiven Systems, dasselbe gilt aber für andere Systeme.
Sicherheitslücke im Attribut
Versuchen wir, schädlichen Code über ein HTML-Attribut in die Seite einzuschleusen, wie wir es oben gezeigt haben. Nehmen wir ein Template in Twig, das ein Bild rendert:
<img src={{ imageFile }} alt={{ imageAlt }}>
Beachten Sie, dass um die Attributwerte keine Anführungszeichen stehen. Der Coder hat sie womöglich vergessen, das kommt einfach vor. In React wird der Code zum Beispiel so geschrieben, ohne Anführungszeichen, und ein Coder, der zwischen den Sprachen wechselt, vergisst sie leicht.
Ein Angreifer fügt als Bildbeschriftung die geschickt gebaute Zeichenfolge foo onload=alert('Hacked!') ein. Wir
wissen bereits, dass Twig nicht feststellen kann, ob eine Variable im Fluss des HTML-Texts, innerhalb eines Attributs, in einem
HTML-Kommentar usw. ausgegeben wird; kurz gesagt, es unterscheidet keine Kontexte. Und es wandelt lediglich mechanisch die Zeichen
< > & ' " in HTML-Entities um. Der entstehende Code sieht also so aus:
<img src=photo0145.webp alt=foo onload=alert('Hacked!')>
Eine Sicherheitslücke ist entstanden!
Ein gefälschtes Attribut onload ist Teil der Seite geworden, und der Browser führt es unmittelbar nach dem Laden
des Bildes aus.
Sehen wir nun, wie Latte mit demselben Template umgeht:
<img src={$imageFile} alt={$imageAlt}>
Latte sieht das Template genauso wie Sie. Anders als Twig versteht es HTML und weiß, dass die Variable als Wert eines Attributs ausgegeben wird, das nicht in Anführungszeichen steht. Deshalb ergänzt es sie. Fügt ein Angreifer dieselbe Beschriftung ein, sieht der entstehende Code so aus:
<img src="photo0145.webp" alt="foo onload=alert('Hacked!')">
Latte hat XSS erfolgreich verhindert.
Eine Variable in JavaScript ausgeben
Dank kontextsensitivem Escaping lassen sich PHP-Variablen innerhalb von JavaScript ganz natürlich verwenden.
<p onclick="alert({$movie})">{$movie}</p>
<script>var movie = {$movie};</script>
Enthält die Variable $movie den String 'Amarcord & 8 1/2', entsteht die folgende Ausgabe.
Beachten Sie das unterschiedliche Escaping innerhalb von HTML gegenüber dem innerhalb von JavaScript und noch einmal ein anderes
im Attribut onclick:
<p onclick="alert("Amarcord & 8 1/2")">Amarcord & 8 1/2</p>
<script>var movie = "Amarcord & 8 1/2";</script>
Prüfung von Links
Latte prüft automatisch, ob eine Variable, die in URL-Attributen wie src, href, action,
formaction oder data am Element <object> verwendet wird, eine sichere URL enthält.
Es lässt gängige Protokolle zu (http, https, ftp, mailto, tel,
sms) sowie relative URLs und blockiert potenziell gefährliche wie javascript:.
{var $link = 'javascript:attack()'}
<a href={$link}>hier klicken</a>
Gibt aus:
<a href="">hier klicken</a>
Die Prüfung lässt sich mit dem Filter nocheck abschalten.
Client-seitige Frameworks
Frameworks wie Vue oder Angular behandeln einen Teil der Seite als eigenes Template und interpretieren die doppelten
geschweiften Klammern {{ ... }} darin als Ausdruck. Gelingt es einem Angreifer, eine solche Sequenz in eine
ausgegebene Variable zu bekommen, wertet das Framework sie nach dem Laden der Seite im Browser aus, obwohl auf der Serverseite gar
kein XSS stattgefunden hat.
Latte verhindert das. Beim Ausgeben in HTML-Text wandelt es das Paar {{ in {<!-- -->{ um; der
leere Kommentar ist für den Leser unsichtbar, verhindert aber, dass das Framework seinen eigenen Tag erkennt. Jedes weitere
Vorkommen des Zeichens { wird durch die Entity { ersetzt (innerhalb von Attributwerten wird
jedes { so escapt).
{var $query = 'Hi {{ constructor.constructor("alert(1)")() }}'}
<h1>Suche: {$query}</h1>
Gibt aus:
<h1>Suche: Hi {<!-- -->{ constructor.constructor("alert(1)")() }}</h1>
Der Schutz wirkt automatisch und erfordert keine Konfiguration.
Grenzen von Latte
Latte ist kein vollständiger Schutz vor XSS für die gesamte Anwendung. Wir wären unglücklich, wenn Sie bei der Verwendung von Latte aufhörten, über Sicherheit nachzudenken. Das Ziel von Latte ist sicherzustellen, dass ein Angreifer die Struktur der Seite nicht verändern und keine HTML-Elemente oder -Attribute fälschen kann. Es prüft jedoch nicht die inhaltliche Richtigkeit der ausgegebenen Daten. Ebenso wenig die Korrektheit des Verhaltens von JavaScript. Das geht über die Zuständigkeit des Templating-Systems hinaus. Die Richtigkeit der Daten zu prüfen, vor allem der vom Benutzer eingegebenen und damit nicht vertrauenswürdigen, ist eine wichtige Aufgabe des Programmierers.
Wollen Sie Ihr Wissen über das Escaping in den einzelnen Kontexten testen? Probieren Sie das Quiz zur Sicherheitslücke XSS.