HTML-Entity Encoder / Decoder
Konvertieren Sie Sonderzeichen in HTML-Entitäten und zurück.
Gängige HTML-Entitäten
| Zeichen | Entität | Numerisch | Beschreibung |
|---|---|---|---|
| & | & | & | Et-Zeichen |
| < | < | < | Kleiner als |
| > | > | > | Größer als |
| " | " | " | Doppeltes Anführungszeichen |
| ' | ' | ' | Apostroph |
| |   | Geschütztes Leerzeichen | |
| © | © | © | Copyright |
| ® | ® | ® | Eingetragene Marke |
| ™ | ™ | ™ | Marke |
| € | € | € | Eurozeichen |
Warum HTML-Entitäten verwenden?
Zeichen wie <, > und & haben in HTML eine besondere Bedeutung. Wenn Sie sie wörtlich in Ihrem HTML einbinden, interpretiert der Browser sie als Code, nicht als Inhalt. Diese Zeichen als Entitäten zu kodieren, verhindert Renderprobleme und Cross-Site-Scripting-Schwachstellen (XSS).
Häufige Fragen
Was ist der Unterschied zwischen benannten und numerischen Entitäten?
Benannte Entitäten verwenden beschreibende Namen (&, ©), während numerische Entitäten Unicode-Codepunkte (&, ©) nutzen. Beide werden identisch dargestellt. Benannte Entitäten sind lesbarer; numerische Entitäten funktionieren für jedes Unicode-Zeichen.
Muss ich alle Sonderzeichen kodieren?
Mindestens müssen Sie &, <, > und " in HTML-Inhalt und Attributwerten kodieren. Moderne Browser behandeln die meisten anderen Zeichen nativ, sofern Ihr Dokument UTF-8-kodiert ist.
Drei Formen, ein Zeichen
Eine HTML-„Entity“, formell eine Zeichenreferenz: ist eine Escape-Sequenz, die ein Zeichen mithilfe einer Folge gewöhnlicher ASCII-Zeichen darstellt. Der HTML Living Standard definiert drei konkrete syntaktische Formen:
- Benannt:
&gefolgt von einem Namen aus der WHATWG-Tabelle benannter Zeichenreferenzen, abgeschlossen durch ein Semikolon. Beispiel:©für ©. - Dezimal-numerisch:
&#gefolgt vom Unicode-Codepunkt zur Basis 10, abgeschlossen durch ein Semikolon. Beispiel:©. - Hexadezimal-numerisch:
&#xgefolgt vom Codepunkt zur Basis 16, abgeschlossen durch ein Semikolon. Beispiel:©.
Alle drei Formen sind beim Rendern austauschbar: ©, © und © erzeugen alle das sichtbare Zeichen ©, weil sie alle auf den Unicode-Codepunkt U+00A9 aufgelöst werden. Die Wahl zwischen ihnen ist eine Frage der Lesbarkeit des Quellcodes, nicht des Browserverhaltens. Hex entspricht eher veröffentlichten Unicode-Tabellen (die die U+XXXX-Notation verwenden), sodass ♥ der offiziellen Notation U+2665 näher kommt als ♥. Numerische Referenzen funktionieren für jedes Unicode-Zeichen, einschließlich Emoji der astralen Ebene, 😀 rendert als 😀 (U+1F600 GRINNING FACE).
Warum Entities existieren
Drei verschiedene historische und praktische Gründe:
- Um Zeichen zu maskieren, die in HTML syntaktische Bedeutung haben. Der Parser verwendet bestimmte ASCII-Zeichen als Steuersymbole.
<öffnet ein Tag,>schließt eines,&leitet eine Referenz ein, und die Anführungszeichen begrenzen Attributwerte. Wenn eines davon als wörtlicher Text erscheinen soll, müssen Sie es maskieren. - Um Zeichen darzustellen, die in der Dokumentkodierung nicht verfügbar sind. Bevor UTF-8 im Web universell wurde (es überschritt die 50-%-Marke erst um 2010), wurde das meiste HTML als US-ASCII, ISO-8859-1 oder Windows-1252 ausgeliefert. In diesen Einzelbyte-Kodierungen ließen sich Zeichen wie ©, €, ≈ oder α schlicht nicht durch ein wörtliches Byte ausdrücken.
©,€oder≈zu schreiben, war die einzige Möglichkeit, diese Codepunkte zu erreichen. - Um die Absicht des Autors bei unsichtbaren oder mehrdeutigen Zeichen zu signalisieren. Selbst auf einer UTF-8-Seite ist ein wörtliches geschütztes Leerzeichen (U+00A0) optisch identisch mit einem normalen Leerzeichen,
zu schreiben, macht die Absicht für jeden, der den Quelltext liest, offensichtlich.
Das W3C empfiehlt nun, wo möglich wörtliche Unicode-Zeichen statt Entities zu verwenden, „aus Gründen der Barrierefreiheit und Lesbarkeit“. Entities bleiben nützlich für die fünf erforderlichen Maskierungen sowie für wirklich unsichtbare oder mehrdeutige Zeichen.
Die großen Fünf
Die fünf Zeichen, die Sie beim Einfügen nicht vertrauenswürdiger Inhalte in HTML unbedingt maskieren müssen, sind <, >, &, " und '. Das OWASP Cross-Site Scripting Prevention Cheat Sheet zählt sie als die minimal erforderliche Maskierungsmenge auf:
| Zeichen | Benannt | Dezimal | Hex |
|---|---|---|---|
| < | < | < | < |
| > | > | > | > |
| & | & | & | & |
| " | " | " | " |
| ' | ' / ' | ' | ' |
Die Faustregel: Wann immer Sie nicht vertrauenswürdigen Text in HTML-Ausgabe einfügen, maskieren Sie zuerst diese fünf Zeichen. Dies zu versäumen, ist die Grundursache der überwältigenden Mehrheit gespeicherter und reflektierter XSS-Schwachstellen.
Die Apostroph-Falle
' ist kein Teil von HTML 4, es wurde ursprünglich nur von XML 1.0 definiert und in XHTML 1.0 übernommen. Internet Explorer vor Version 9 (veröffentlicht 2011) weigerte sich, es als ' zu rendern, und zeigte den wörtlichen Text ' an. Die Entity wurde eigens zu HTML5 hinzugefügt und ist nun in jedem modernen Browser sicher, aber für maximale browser- und spezifikationsübergreifende Kompatibilität empfehlen OWASP und die meisten unternehmensgerechten Bereinigungsbibliotheken weiterhin, beim Maskieren einfacher Anführungszeichen ' statt ' auszugeben, besonders in sicherheitskritischem Code.
Wann kodiert wird und wann nicht
Die Kodierungsentscheidung hängt davon ab, wo der Text in der Ausgabe landet, nicht davon, was er enthält. Das ist der am häufigsten missverstandene Punkt der HTML-Sicherheit. Die OWASP-Leitlinie unterscheidet die Kontexte:
- HTML-Elementinhalt: maskieren Sie
< > & "(und'aus Vorsicht). - HTML-Attributwerte: maskieren Sie dieselben plus das Anführungszeichen; verwenden Sie immer Attribute in Anführungszeichen.
- JavaScript-Kontext: verwenden Sie JavaScript-Maskierung, nicht HTML-Maskierung:
\xHHoder\uHHHH. - CSS-Kontext: verwenden Sie CSS-Maskierung:
\HHgefolgt von einem Leerzeichen. - URL-/URI-Parameter-Kontext: verwenden Sie Prozentkodierung (
%HH), nicht HTML-Kodierung.
Jeder Kontext hat seine eigenen Maskierungsregeln. Sie zu vermischen, ist selbst eine Schwachstelle, das Prozentkodieren eines < zu %3C schützt beispielsweise nicht vor XSS im HTML-Elementkontext, wo %3C nur der wörtliche Text %3C ist.
Vermeiden Sie Doppelkodierung. Ein häufiger Fehler ist, Daten beim Einlesen ins System zu maskieren, erneut beim Speichern, erneut beim Auslesen und erneut beim Rendern. Das Ergebnis: Der Nutzer tippte 5 < 10, die Datenbank speichert 5 &lt; 10, die Seite rendert 5 < 10 statt des Originals. Die Disziplin lautet: rohes Unicode speichern, einmal kodieren, im Moment der Ausgabe, für den spezifischen Kontext.
HTML-Kodierung vs. URL-Kodierung
Zwei verschiedene Maskierungssysteme für zwei verschiedene Kontexte, die ständig verwechselt werden:
| HTML-Entity | URL / Prozent | |
|---|---|---|
| Standard | HTML Living Standard | RFC 3986 |
| Format | &name; oder &#NN; | %HH (Hex-Byte) |
| Kontext | HTML-Markup, Elementkörper und Attribute | URLs, Query-Strings, formularkodierte Anfragekörper |
| Leerzeichen | (geschützt), niemals ein einfaches Leerzeichen | %20 oder + |
| JS-Funktion | - (vom Parser behandelt) | encodeURIComponent() / encodeURI() |
Eine URL innerhalb eines HTML-Attributwerts erhält beide Maskierungen geschichtet: zuerst Prozentkodierung für URL-unzulässige Zeichen, dann HTML-Kodierung für jedes & < > " in der resultierenden URL. Deshalb werden Query-String-Ampersands innerhalb eines href-Attributs in der HTML-Serialisierung zu &.
Eine kurze Geschichte
HTML 2.0 (RFC 1866, 1995) übernahm SGMLs Entity-Mechanismus mit etwa 50 benannten Entities für ISO Latin 1. HTML 3.2 (W3C, Januar 1997) fügte die mathematischen und Symbol-Entities hinzu. HTML 4.01 (W3C, Dezember 1999) finalisierte drei Entity-Sätze (Latin-1, Special und Symbol) mit insgesamt 252 benannten Entities, was die Quelle der „252“-Zahl ist, die man noch in älteren Tutorials sieht. HTML5 / WHATWG (Living Standard, fortlaufend) übernahm die Tabelle und erweiterte sie dramatisch auf über 2.000 Einträge, vor allem um MathML und einen breiteren Unicode-Satz abzudecken. XML 1.0 (1998) definiert seinen eigenen minimalen Satz aus nur den großen Fünf (< > & " '), dieser minimale Satz ist der Ursprung von '.
Weitere Fragen
Was sollte ich in modernem Code tatsächlich verwenden?
Produktionscode rollt die Entity-Kodierung im Allgemeinen nicht von Hand, er ruft eine Bibliothek auf. DOMPurify für die clientseitige HTML-Bereinigung. html.escape() in Pythons Standardbibliothek. htmlspecialchars() in PHP. html/template in Go (Auto-Maskierung standardmäßig aktiv). OWASP Java Encoder für Java. In React maskiert das Schreiben von <div>{userInput}</div> automatisch; die Ausweichluke dangerouslySetInnerHTML ist so benannt, um von einer beiläufigen Nutzung abzuraten. Ein eigenständiger Encoder wie dieser ist als Plausibilitätsprüfung / Debugging-Werkzeug nützlich, kein Ersatz für jene Bibliotheken.
Was ist mit Tags in E-Mail-Vorlagen?
Ältere E-Mail-Programme (insbesondere Outlook) interpretieren ein nicht kodiertes & als fehlerhaftes Attribut und entfernen möglicherweise umgebendes Markup. HTML-E-Mail-Entwickler lernen, jedes Sonderzeichen vorsorglich als Entity zu kodieren. Dasselbe gilt für Forensysteme im BBCode-Stil, die Inhalte vor dem Speichern umschreiben; Hin- und Rückwege können unerwartete wörtliche Entities einführen.
Was ist textContent vs. innerHTML in JavaScript?
Die wichtigste XSS-Präventionsregel in reinem JavaScript: Verwenden Sie element.textContent = userInput statt element.innerHTML = userInput. Das Setzen von textContent schreibt den String als wörtlichen Text, der Browser übernimmt die gesamte Maskierung intern. Das Setzen von innerHTML parst den String als HTML und führt alle darin enthaltenen <script>-Tags oder Event-Handler-Attribute aus. Wenn Markup wirklich erforderlich ist, verwenden Sie zuerst eine Bibliothek wie DOMPurify zur Bereinigung.
Kann der Encoder mit Emojis umgehen?
Ja, über numerische Referenzen. Es gibt keine benannten Entities für Emojis, sie verwenden alle die numerische Form. 😀 rendert als 😀, ❤️ als das rote Herz ❤️ (Herz-Codepunkt plus Emoji-Präsentationsselektor). Der Browser übernimmt die implizite UTF-16-Surrogatpaar-Umwandlung intern; Sie sollten die Surrogathälften nicht manuell schreiben.
Werden Daten an einen Server gesendet?
Nein. Kodierung und Dekodierung sind reine String-Transformationen, die vollständig in Ihrem Browser über JavaScript laufen. Nichts von Ihrer Eingabe wird hochgeladen; die Seite funktioniert offline, sobald sie geladen ist. Das ist wichtig, weil cloudbasierte Encoder, die Ihre Test-Nutzlast hin- und zurückschicken, selbst zu einem XSS-Vektor werden können, wenn die Testseite kompromittiert ist.