Eine HTML-Entity ist eine Schreibweise für ein Zeichen, mit der der Browser es als Text anzeigt, statt es als Markup zu behandeln. Schreiben Sie ein rohes < in Ihren Inhalt, beginnt der Browser, ein Tag zu lesen; schreiben Sie stattdessen <, rendert er ein wörtliches < auf der Seite. Dieser Tausch ist die ganze Idee hinter dem HTML-Entity-Encoding.
Fünf Zeichen tragen in HTML eine Sonderbedeutung und werden am häufigsten escapt: <, >, &, " und '. Sie escapen sie aus zwei Gründen. Der erste ist die Darstellung: Sie möchten Code oder Markup als Text zeigen. Der zweite, wichtigere Grund ist die Sicherheit: Das Escapen nicht vertrauenswürdiger Eingaben ist die Grundlage dafür, Cross-Site-Scripting (XSS) zu verhindern.
Es gibt drei austauschbare Schreibweisen für jede Entity, benannt (<), dezimal (<) und hexadezimal (<), und sie alle lösen sich zum selben Zeichen auf. Die kniffligere Frage ist, wann man escapt und womit, denn die richtige Antwort hängt davon ab, wo der Wert landet: im HTML-Text, in einem Attribut, in einem Skript oder in einer URL. Dieser Leitfaden führt durch die Notationen, die reservierte Zeichenmenge, eine Kontext-Entscheidungsmatrix und die Fallstricke, die am häufigsten zuschlagen.
Was ist eine HTML-Entity? (Aufbau)
Eine HTML-Entity, auch Zeichenreferenz genannt, ist ein kurzer Code, der für ein einzelnes Zeichen steht. Jede Entity beginnt mit einem Ampersand & und endet mit einem Semikolon ;. Was dazwischen steht, bestimmt, welches Zeichen Sie erhalten.
Es gibt drei Formen:
&name;— eine benannte Referenz, etwa<oder©.&#decimal;— eine dezimale numerische Referenz, etwa<.&#xhex;— eine hexadezimale numerische Referenz, etwa<.
Der Browser liest die Referenz, schlägt das Zeichen nach, auf das sie verweist, und rendert dieses eine Zeichen. Am sichtbaren Ergebnis ändert sich nichts: < und ein rohes < werden identisch angezeigt. Der einzige Unterschied ist, dass die Entity als Text behandelt wird, nie als Beginn eines Tags.
Die drei Notationen: benannt, dezimal, hexadezimal
Alle drei Notationen verweisen auf denselben Unicode-Codepunkt; sie unterscheiden sich nur in der Schreibweise. Eine benannte Entity ist die lesbare Form, existiert aber nur für Zeichen, die einen definierten Namen haben. Eine dezimale Entity schreibt den Codepunkt zur Basis 10. Eine hexadezimale Entity schreibt denselben Codepunkt zur Basis 16, was sich eins zu eins auf die U+XXXX-Notation abbildet, die Sie im Unicode-Standard sehen.
| Zeichen | Benannt | Dezimal | Hex |
|---|---|---|---|
< | < | < | < |
& | & | & | & |
© | © | © | © |
é | é | é | é |
Weil Hex die U+XXXX-Form direkt spiegelt (é ist U+00E9, also é), greifen viele Entwickler darauf zurück, wenn sie einen bestimmten Codepunkt dokumentieren oder durchdenken. Für alltägliches Markup lesen sich benannte Entities am besten.
Die fünf reservierten Zeichen, die Sie escapen müssen
Dies sind die HTML-Sonderzeichen, die verändern, wie der Browser ein Dokument parst. Erscheint eines davon in Inhalt, der angezeigt statt ausgeführt werden soll, escapen Sie es.
| Zeichen | Benannt | Dezimal | Hex | Was kaputtgeht, wenn Sie es nicht escapen |
|---|---|---|---|---|
< | < | < | < | Beginnt ein Tag — der Browser liest folgenden Text als Markup |
> | > | > | > | Schließt ein Tag vorzeitig |
& | & | & | & | Beginnt eine Entity — der Rest kann als Referenz fehlinterpretiert werden |
" | " | " | " | Beendet einen doppelt gequoteten Attributwert zu früh |
' | ' | ' | ' | Beendet einen einfach gequoteten Attributwert zu früh |
Die HTML-Ampersand-Entity ist die Wurzel des ganzen Systems. Das &-Zeichen beginnt jede Entity, also muss es zuerst escapt werden. Escapen Sie die spitzen Klammern vor dem Ampersand, escapen Sie das & in den gerade erzeugten Entities erneut. Mehr zu diesem Fallstrick weiter unten.
Wann müssen Sie tatsächlich escapen? (kontextabhängig)
Hier wohnen die meisten Bugs und die meisten Schwachstellen. Das Kernprinzip ist kurz: Escapen Sie zur Ausgabezeit, passend zum Kontext, in dem der Wert landet. Ein Wert, der an einer Stelle sicher ist, ist an einer anderen gefährlich, also muss die angewandte Kodierung zum Ziel passen.
HTML-Elementinhalt
Wenn Sie einen Wert zwischen Tags ablegen (innerhalb eines <p>, eines <div>, eines <td>), escapen Sie <, > und &. Die Anführungszeichen hier zu escapen ist harmlos, aber unnötig. Wenn Sie den Text <strong> als wörtliche Zeichen zeigen wollen, statt das nächste Wort fett zu machen, kodieren Sie ihn zu <strong>, und der Browser gibt das Tag aus, statt es anzuwenden.
HTML-Attributwerte
Innerhalb eines Attributs werden die Anführungszeichen kritisch. Sitzt ein Wert in title="…" und enthält ein nicht escaptes ", beendet es das Attribut zu früh und lässt einen Angreifer neue Attribute anhängen, ein klassischer XSS-Vektor. Escapen Sie " (und idealerweise ') im Attributkontext. Ein Wert wie He said "hi" muss zu He said "hi" werden, um eingeschlossen zu bleiben.
Innerhalb von <script> oder Inline-JavaScript
HTML-Entities helfen hier nicht. Eine Zeichenkette, die in einen <script>-Block oder einen Inline-Event-Handler eingebaut wird, braucht JavaScript- oder JSON-String-Escaping, keine Zeichenreferenzen. " in einem JS-String-Literal zu schreiben, erzeugt die wörtlichen sechs Zeichen, kein Anführungszeichen. Für diesen Kontext greifen Sie zum Tool JSON maskieren und lesen Sie den vollständigen Leitfaden zum JSON-String-Escaping für die \uXXXX-Regeln, die tatsächlich innerhalb von Skripten gelten.
Innerhalb einer URL
Eine URL hat ihr eigenes Escaping-Schema: Prozent-Kodierung. HTML-Entities machen einen Wert nicht URL-sicher. Die Zeichenkette a&b c gehört in eine Query als a%26b%20c, nicht als a&b c. Das Leerzeichen würde die URL sonst brechen, und das & würde weiterhin Parameter trennen. Verwenden Sie dafür den URL-Dekodierer & -Kodierer und den Leitfaden zum URL-Encoding und -Decoding für die vollständigen Regeln zu reservierten versus nicht reservierten Zeichen.
Die Entscheidungsmatrix
| Kontext | Escapen mit | Beispiel | Falsche Wahl, die scheitert |
|---|---|---|---|
| HTML-Elementinhalt | HTML-Entities (< > &) | <strong> → <strong> | Ein rohes < injiziert ein Tag |
| HTML-Attributwert | HTML-Entities (" ' kritisch) | "hi" → "hi" | Ein nicht escaptes " bricht aus |
<script> / Inline-JS | JS-/JSON-String-Escaping | " → \" | HTML-Entities sind in JS wirkungslos |
| URL / Query-String | Prozent-Kodierung | Leerzeichen → %20 | & und Entities brechen die URL trotzdem |
Benannt vs. numerisch: was sollten Sie verwenden?
Benannte Entities sind lesbar und der richtige Standard für die gängigen reservierten Zeichen und bekannten Symbole wie <, &, © und —. Sie existieren jedoch nur für Zeichen, die einen definierten Namen haben. Numerische Entities, dezimal oder hex, können jeden Codepunkt kodieren, auch solche ohne Namen, was sie zum universellen Rückfall macht. Wenn Sie nicht garantieren können, dass das verarbeitende System eine bestimmte benannte Entity unterstützt, ist die numerische Form die sichere Wahl.
Warum der Apostroph ' ist und nicht '
Die benannte Entity ' wurde erst mit HTML5 und XML eingeführt. In HTML4 ist sie undefiniert, sodass eine Handvoll älterer Parser und E-Mail-Clients sie als den wörtlichen Text ' rendern statt als Apostroph. Die numerische Referenz ' (und ihr dezimaler Zwilling ') verweist auf genau dasselbe Zeichen, U+0027, und wird von jedem konformen Parser verstanden, der je geschrieben wurde. Gut getestete Escaping-Bibliotheken wie he geben aus genau diesem Grund ' für das einfache Anführungszeichen aus, und ein guter Encoder folgt dieser Konvention, damit die Ausgabe in jedem HTML-, XML- oder Attributkontext sicher abgelegt werden kann.
Zeichensatz vs. Entities: wann Nicht-ASCII kodieren
Ein Zeichensatz wie UTF-8 entscheidet, wie Zeichen als Bytes gespeichert werden. Eine Entity ist eine Möglichkeit, ein Zeichen mit reinem ASCII zu schreiben (&, #, ;, Buchstaben, Ziffern). Das sind unterschiedliche Schichten, und sie zu verwechseln führt zu unnötiger Kodierung.
Auf einer UTF-8-Seite (also nahezu jeder modernen Seite, die <meta charset="utf-8"> deklariert) sind akzentuierte Buchstaben, Gedankenstriche und Emoji gültige rohe Zeichen. Lassen Sie é, — und 😀 genau so, wie sie sind. Alles in Entities zu kodieren ist nur dann relevant, wenn der Text einen veralteten Single-Byte-Zeichensatz oder ein System überstehen muss, das rohes UTF-8 verstümmelt; für solche Fälle existiert ein Modus „alles Nicht-ASCII kodieren“. Wenn Sie unsicher sind, wie Bytes, Codepunkte und Zeichen zusammenhängen, legt der Leitfaden zum UTF-8-, UTF-16- und Unicode-Encoding das Modell dar.
Häufige HTML-Entity-Fallstricke
Das & zuletzt zu escapen verursacht Doppel-Escaping
Die Reihenfolge zählt. Ersetzen Sie < und > vor &, bekommen die gerade erzeugten Entities (<, >) ihr führendes & ebenfalls escapt, sodass aus < am Ende &lt; wird und es als wörtlicher Text < rendert. Escapen Sie immer zuerst &, dann den Rest. Diese eine Regel verhindert den häufigsten Encoding-Bug überhaupt.
Bereits escapten Text doppelt kodieren
Bereits escapten Text erneut durch einen Encoder zu schicken kodiert ihn ein zweites Mal. Aus & wird &amp;, und der Besucher sieht & auf der Seite statt &. Escapen Sie genau einmal, zur Ausgabezeit. Wenn ein Wert mehrere Schichten durchläuft, stellen Sie sicher, dass nur eine davon escapt.
Mojibake beim Dekodieren
Die andere Richtung hat ihre eigene Falle. Dekodieren Sie mit dem falschen Zeichensatz oder dekodieren Sie zweimal, erhalten Sie verstümmelte Ausgabe, das klassische Mojibake. Zeigt eine Seite wörtliches &lt;, wo Sie < erwartet haben, fügen Sie es in den HTML-Entity-Decoder ein, um genau zu sehen, wozu die Entities sich auflösen; er verarbeitet benannte, dezimale, hexadezimale und sogar veraltete unterminierte Referenzen wie © ohne abschließendes Semikolon.
Escaping als vollständige XSS-Kur missverstehen
Escaping ist die erste Verteidigungslinie, nicht die einzige. Weil HTML mehrere Kontexte mit unterschiedlichen Regeln hat, hinterlässt das Escapen für den falschen ein Loch: Anführungszeichen in Attributen, JS-Escaping im Skript, Prozent-Kodierung in URLs. Kombinieren Sie korrektes, kontextabhängiges Escaping mit einer Content-Security-Policy und dem Auto-Escaping Ihres Frameworks. Betrachten Sie Entity-Encoding als das Fundament, mit CSP und Framework-Standardeinstellungen obendrauf.
Wie man Entities in der Praxis kodiert und dekodiert
Wenn Sie HTML von Hand aufbauen, escapen Sie es selbst. Hier ist ein korrektes escapeHtml(), das die &-zuerst-Reihenfolge berücksichtigt, plus die bessere Praxis für echten Anwendungscode.
// Die fünf reservierten Zeichen und ihre sicheren Entities:
// < → < > → > & → & " → " ' → '
function escapeHtml(str) {
return str
.replace(/&/g, '&') // & ZUERST, damit spätere Entities nicht doppelt escapt werden
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, '''); // numerische Form — sicher in HTML4, HTML5 und XML
}
const userInput = `<a href="x">Tom & Jerry's</a>`;
const safe = escapeHtml(userInput);
// → <a href="x">Tom & Jerry's</a>
// Besser im App-Code: lassen Sie die Plattform für Sie escapen.
// el.textContent = userInput; // der Browser escapt; kein manuelles replace
// React / Vue / Angular escapen interpolierten Text standardmäßig
// Server-Templates (Jinja, ERB, Blade) escapen automatisch, sofern man es nicht abschaltet
Die selbstgebaute Funktion ist nützlich, um zu verstehen, was passiert, und für einmalige Konvertierungen, doch in der Produktion sollten Sie den eingebauten Weg vorziehen. element.textContent zu setzen lässt den Browser für Sie escapen, und moderne Frameworks escapen interpolierte Werte automatisch. Behalten Sie manuelles Escaping für die Fälle vor, die die Plattform nicht abdeckt.
Für Ad-hoc-Arbeit escapt der HTML-Entity-Encoder die reservierte Zeichenmenge (benannt, dezimal oder hex), und der HTML-Entity-Decoder macht das rückgängig. Die beiden sind exakte Umkehrungen für die reservierten Zeichen, sodass Sie Text verlustfrei durch beide hin- und zurückführen können.
Häufig gestellte Fragen
Was ist eine HTML-Entity?
Eine HTML-Entity ist ein kurzer Code, der mit & beginnt und mit ; endet und ein einzelnes Zeichen darstellt. Der Browser rendert das Zeichen, auf das die Entity verweist, statt es als Markup zu behandeln. Zum Beispiel zeigt < ein wörtliches < an und & ein wörtliches &.
Welche Zeichen muss ich in HTML escapen?
Die fünf reservierten HTML-Sonderzeichen: <, >, &, " und '. Im Elementinhalt brauchen Sie vor allem <, > und &; in Attributwerten werden zusätzlich die Anführungszeichen " und ' kritisch. Escapen Sie das Ampersand & zuerst, damit die anderen Entities nicht doppelt escapt werden.
Sollte ich benannte oder numerische (dezimale/hexadezimale) Entities verwenden?
Verwenden Sie benannte Entities (<, ©) für die Lesbarkeit bei den gängigen Zeichen, da sie leicht zu erkennen sind. Verwenden Sie numerische Entities (dezimal < oder hex <), wenn Sie ein Zeichen ohne definierten Namen kodieren müssen oder wenn Sie nicht garantieren können, dass der Konsument eine bestimmte benannte Entity unterstützt. Beide Formen verweisen auf denselben Codepunkt.
Schützen HTML-Entities vor XSS?
Sie sind das Fundament, sofern korrekt angewandt. Die fünf reservierten Zeichen zu escapen, bevor nicht vertrauenswürdige Eingaben in HTML-Element- oder -Attributinhalt gelangen, stoppt Tag- und Skript-Injektion. Aber Escaping ist kontextabhängig: Skriptblöcke brauchen JavaScript-Escaping und URLs brauchen Prozent-Kodierung. Kombinieren Sie korrektes, kontextabhängiges Escaping mit CSP und dem Auto-Escaping des Frameworks.
Warum zeigt meine Seite &lt; statt <?
Das ist Doppel-Escaping. Der Text wurde zweimal kodiert, oder das & wurde nach den spitzen Klammern escapt, sodass das & in < zu & wurde. Der Besucher sieht dann < als wörtlichen Text. Escapen Sie genau einmal und escapen Sie immer zuerst &. Das Decoder-Tool kann bestätigen, wozu die Entities sich auflösen.
Muss ich Zeichen wie é, — oder Emoji escapen?
Meist nein. Auf einer Seite, die <meta charset="utf-8"> deklariert, sind akzentuierte Buchstaben, Gedankenstriche und Emoji gültige rohe Zeichen und brauchen keine Kodierung. Lassen Sie sie unverändert. Kodieren Sie Nicht-ASCII nur, wenn der Text einen veralteten Single-Byte-Zeichensatz oder ein System durchlaufen muss, das rohes UTF-8 beschädigt.