Was sind HTML-Entities?
HTML-Entities sind spezielle Textsequenzen, die verwendet werden, um Zeichen darzustellen, die entweder eine reservierte Bedeutung in HTML haben oder nicht einfach getippt oder übertragen werden können. Eine Entity beginnt mit einem Ampersand (&) und endet mit einem Semikolon (;). Zwischen diesen Begrenzern steht entweder ein beschreibender Name (eine benannte Entity wie &) oder ein numerischer Codepunkt (eine numerische Entity wie & oder &).
Auf den ersten Blick mögen Entities wie ein unbedeutendes typografisches Detail erscheinen. In Wirklichkeit sind sie ein Eckpfeiler der Web-Sicherheit, Internationalisierung und zuverlässigen Browser-Darstellung. Jeder Webentwickler, der mit dynamischen Inhalten arbeitet – Benutzereingaben, CMS-Daten, E-Mail-Vorlagen oder Templating-Engines –, muss verstehen, wie und wann HTML-Entities kodiert werden müssen.
Eine kurze Geschichte der HTML-Entities und Zeichenkodierung
Die ASCII-Ära (1960er–1980er Jahre)
Der American Standard Code for Information Interchange (ASCII) definierte 128 Zeichen: die 26 englischen Buchstaben (Groß- und Kleinschreibung), Ziffern, Satzzeichen und Steuercodes. Dies reichte für amerikanisches Englisch aus, war aber für den Rest der Weltsprachen völlig unzureichend.
Latin-1 / ISO-8859-1 (1980er–1990er Jahre)
ISO-8859-1 (auch Latin-1 genannt) erweiterte ASCII auf 256 Zeichen, indem das 8. Bit verwendet wurde. Es fügte akzentuierte Zeichen hinzu, die in westeuropäischen Sprachen verwendet werden (é, ü, ñ usw.). HTML 2.0 und HTML 3.2 übernahmen Latin-1 formal als ihren Referenzzeichensatz, und zu dieser Zeit wurden benannte HTML-Entities für viele dieser Zeichen definiert – Entities wie é (é), ü (ü) und ñ (ñ).
Das Problem: 256 Zeichen konnten immer noch nicht Japanisch, Arabisch, Chinesisch, Koreanisch oder Hunderte anderer Schriften abdecken. Verschiedene Regionen erfanden inkompatible Kodierungen (Shift-JIS, Big5, KOI8-R…), was zum "Mojibake"-Problem führte – verstümmelter Text, wenn Kodierungen vermischt wurden.
Unicode und UTF-8 (1991–heute)
Das Unicode-Konsortium veröffentlichte 1991 seinen ersten Standard mit dem Ziel, jedem Zeichen in jedem Schriftsystem einen eindeutigen Codepunkt zuzuweisen. Heute deckt Unicode über 140.000 Zeichen in mehr als 150 Schriften ab.
UTF-8, das 1992 von Ken Thompson und Rob Pike eingeführt wurde, kodiert Unicode-Codepunkte als 1–4 Bytes und ist abwärtskompatibel mit ASCII. Es wurde in den 2000er Jahren zur dominierenden Kodierung für das Web. Stand 2024 nutzen über 98 % der Webseiten UTF-8.
Warum sind Entities in einer UTF-8-Welt immer noch wichtig?
Wenn wir jedes Zeichen mit UTF-8 kodieren können, warum existieren Entities dann noch? Dafür gibt es drei Gründe:
- Reservierte Zeichen:
<,>, und&haben in HTML-Markup eine spezielle Bedeutung. Selbst in UTF-8-Dokumenten müssen Sie diese maskieren, um sie wörtlich anzuzeigen. - Attribut-Begrenzer:
"und'begrenzen Attributwerte und müssen innerhalb dieser Werte maskiert werden. - Leerraum-Steuerung:
(geschütztes Leerzeichen) steuert das Layout auf eine Weise, die normale Leerzeichen nicht können.
Kernkonzepte: Wie HTML-Entities funktionieren
Benannte Entities
Benannte Entities sind die für Menschen am besten lesbare Form. Sie verwenden einen mnemonischen Namen, der von der Beschreibung des Zeichens abgeleitet ist. HTML5 definiert über 2.000 benannte Entities.
<!-- Verwendung benannter Entities -->
<p>Brot & Butter</p> <!-- Anzeige: Brot & Butter -->
<p>3 < 5 und 10 > 7</p> <!-- Anzeige: 3 < 5 und 10 > 7 -->
<p>Copyright © 2026</p> <!-- Anzeige: Copyright © 2026 -->
<p>Preis: 49€</p> <!-- Anzeige: Preis: 49€ -->
Numerische Entities: Dezimal und Hexadezimal
Jedes Unicode-Zeichen kann durch seinen Codepunkt in entweder dezimaler oder hexadezimaler Form referenziert werden:
- Dezimal:
&#gefolgt vom dezimalen Codepunkt — z. B.<für<(U+003C) - Hexadezimal:
&#xgefolgt vom Hex-Codepunkt — z. B.<für<
Beide Formen sind gleichwertig. Hexadezimal ist in der technischen Dokumentation üblich, da Unicode-Codepunkte normalerweise in Hex (U+003C) ausgedrückt werden.
<!-- Alle drei sind gleichwertige Wege, um < anzuzeigen -->
<
<
<
Die 5 kritischen Sicherheits-Entities
Diese fünf Zeichen bilden die Grundlage der Verteidigung gegen HTML-Injektionen:
| Zeichen | Benannte Entity | Dezimal | Hex | Kontext |
|---|---|---|---|---|
< |
< |
< |
< |
Öffnet HTML-Tags |
> |
> |
> |
> |
Schließt HTML-Tags |
& |
& |
& |
& |
Beginnt Entities |
" |
" |
" |
" |
Doppelt zitierte Attribute |
' |
' |
' |
' |
Einfach zitierte Attribute |
Kodieren Sie immer alle fünf, wenn Sie Benutzereingaben in HTML widerspiegeln.
HTML-Entity-Referenztabelle
| Zeichen | Benannte Entity | Dezimal | Hex | Verwendung |
|---|---|---|---|---|
< |
< |
< |
< |
Tag-Begrenzer |
> |
> |
> |
> |
Tag-Begrenzer |
& |
& |
& |
& |
Entity-Präfix |
" |
" |
" |
" |
Attributwerte |
' |
' |
' |
' |
Attributwerte |
|
|
  |
  |
Geschütztes Leerzeichen |
© |
© |
© |
© |
Urheberrecht |
® |
® |
® |
® |
Eingetragene Marke |
™ |
™ |
™ |
™ |
Marke |
€ |
€ |
€ |
€ |
Euro-Zeichen |
— |
— |
— |
— |
Geviertstrich (Em-Dash) |
– |
– |
– |
– |
Halbgeviertstrich (En-Dash) |
XSS-Prävention: Warum Kodierung Ihre Website schützt
Cross-Site Scripting (XSS) ist eine der am weitesten verbreiteten Web-Sicherheitslücken. Es tritt auf, wenn ein Angreifer bösartige Skripte in Inhalte einschleust, die dann an andere Benutzer ausgeliefert werden. Die HTML-Entity-Kodierung ist die primäre Verteidigung.
Der klassische XSS-Angriff
Stellen Sie sich eine Suchfunktion vor, die die Abfrage des Benutzers zurückgibt:
<!-- ANFÄLLIG: Benutzereingabe wird direkt eingefügt -->
<p>Sie haben gesucht nach: <?php echo $_GET['q']; ?></p>
Ein Angreifer erstellt eine URL wie:
https://example.com/search?q=<script>document.cookie</script>
Der Browser rendert das <script>-Tag und führt den Code des Angreifers aus. Mit document.cookie stehlen sie Sitzungs-Tokens. Mit fetch() exfiltrieren sie Daten an einen vom Angreifer kontrollierten Server.
Die Lösung: Kodierung bei der Ausgabe
<!-- SICHER: Alle Ausgaben kodieren -->
<p>Sie haben gesucht nach: <?php echo htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8'); ?></p>
Jetzt sieht der Browser:
<p>Sie haben gesucht nach: <script>document.cookie</script></p>
Das Skript wird als harmloser Text angezeigt – es findet keine Ausführung statt.
Praktische Code-Beispiele
JavaScript: Sichere DOM-Manipulation
Der sicherste Weg, benutzergenerierte Inhalte in JavaScript einzufügen, ist textContent, da dieser HTML niemals interpretiert:
// SICHER: textContent parst niemals HTML
const el = document.getElementById('output');
el.textContent = userInput; // maskiert automatisch alles
// GEFÄHRLICH: innerHTML parst und führt HTML aus
el.innerHTML = userInput; // Tun Sie dies NIEMALS mit nicht vertrauenswürdigen Eingaben
Wenn Sie HTML-Strings in JavaScript erstellen müssen, maskieren Sie diese immer zuerst:
function escapeHtml(str) {
return str
.replace(/&/g, '&') // muss an erster Stelle stehen
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
const safe = `<p>Sie haben gesucht nach: ${escapeHtml(userInput)}</p>`;
Hinweis: Maskieren Sie & immer zuerst – wenn Sie zuerst < maskieren würden, würde das & in < selbst zu &lt; maskiert werden, was zu einer doppelten Kodierung führen würde.
PHP: htmlspecialchars() und htmlentities()
PHP bietet zwei Hauptfunktionen für die HTML-Kodierung:
// htmlspecialchars: kodiert nur die 5 kritischen Zeichen
$safe = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// htmlentities: kodiert ALLE Zeichen mit entsprechenden benannten Entities
$safe = htmlentities($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
Hauptunterschied: htmlspecialchars() kodiert nur <, >, &, " und '. htmlentities() kodiert auch akzentuierte Buchstaben und Symbole wie é → é. Für UTF-8-Dokumente wird htmlspecialchars() normalerweise bevorzugt – UTF-8 kann alle Zeichen direkt darstellen; nur die gefährlichen fünf müssen maskiert werden.
Geben Sie immer ENT_QUOTES an, um beide Arten von Anführungszeichen zu kodieren, und geben Sie immer 'UTF-8' als Zeichensatz an.
Python: html.escape()
import html
# Grundlegendes Maskieren
safe = html.escape(user_input)
# Auch einfache Anführungszeichen maskieren (quote=True ist Standard seit Python 3.2)
safe = html.escape(user_input, quote=True)
# Beispiel
user_input = '<script>alert("XSS")</script>'
print(html.escape(user_input))
# Ausgabe: <script>alert("XSS")</script>
HTML-Templates (Jinja2, Django, Handlebars)
Die meisten modernen Templating-Systeme maskieren standardmäßig automatisch:
<!-- Jinja2 / Django: standardmäßig automatisch maskiert -->
<p>{{ user_comment }}</p>
<!-- Absichtlich rohes HTML rendern (GEFÄHRLICH bei benutzergesteuerten Inhalten): -->
<p>{{ user_comment | safe }}</p>
<!-- Handlebars: Doppelte geschweifte Klammern maskieren, dreifache nicht -->
<p>{{userComment}}</p> <!-- maskiert — sicher -->
<p>{{{userComment}}}</p> <!-- rohes HTML — gefährlich! -->
Anwendungsfälle in der realen Welt
1. Technische Dokumentation und Code-Blogs
Wenn Sie über HTML schreiben, müssen Sie häufig Codebeispiele zeigen, die <, >, und & enthalten. Mit Entities können Sie diese als wörtliche Zeichen anzeigen, ohne die Seitenstruktur zu zerstören:
<pre><code>
Verwenden Sie <div> und </div>, um Abschnitte zu umschließen.
Das &-Zeichen beginnt eine HTML-Entity.
</code></pre>
2. CMS und benutzergenerierte Inhalte
Jedes CMS, das benutzergenerierten Text speichert und anzeigt, muss HTML-Entities kodieren, bevor es sie auf der Seite ausgibt. Dazu gehören Blog-Kommentare, Forumsbeiträge, Produktbewertungen und Social-Media-Posts. Das Versäumnis, dies zu tun, ist für einen großen Teil der realen XSS-Vorfälle verantwortlich.
3. HTML-E-Mail-Vorlagen
E-Mail-Clients sind bekanntermaßen inkonsistent. Die Verwendung benannter Entities für typografische Zeichen (—, ‘, ’, …) hilft dabei, eine korrekte Darstellung in Gmail, Outlook, Apple Mail und älteren Clients wie Outlook 2007 (der die Rendering-Engine von Word verwendet) sicherzustellen.
4. Typografie und spezielle Symbole
Entities bieten zuverlässigen Zugriff auf typografische Zeichen, die umständlich zu tippen sind oder das Kopieren und Einfügen zwischen Systemen möglicherweise nicht überstehen:
<p>Der Geviertstrich—verwendet für Einschübe—ist ausdrucksstärker als ein Bindestrich.</p>
<p>Sie sagte „Hallo“ und lächelte.</p>
<p>Preis: 29 €</p>
<!-- verhindert, dass "29" und "€" in verschiedene Zeilen umbrochen werden -->
5. Internationalisierung in Altsystemen
In Altsystemen, die UTF-8 nicht zuverlässig verarbeiten können, ermöglichen numerische Entities die Kodierung jedes Unicode-Zeichens:
<!-- Chinesisches Zeichen für "Drache" (U+9F99) als dezimale Entity -->
龙
<!-- Japanisches Hiragana あ (U+3042) -->
あ
Benannte vs. numerische Entities: Vergleich
| Aspekt | Benannt (<) |
Dezimal (<) |
Hexadezimal (<) |
|---|---|---|---|
| Lesbarkeit | Hoch | Mittel | Niedrig |
| Abdeckung | ~2.000 Zeichen | Gesamtes Unicode | Gesamtes Unicode |
| HTML5-Unterstützung | Vollständig | Vollständig | Vollständig |
| XML-Unterstützung | Nur 5 vordefinierte | Vollständig | Vollständig |
| Bestens geeignet für | Häufige Zeichen | Beliebiges Unicode | Technische/Unicode-Refs |
HTML vs. XML: Ein kritischer Unterschied
XML definiert nur 5 Entities vor (<, >, &, ", '). Alle anderen benannten Entities wie © oder sind in XML undefiniert, es sei denn, sie werden in einer DTD deklariert.
<!-- UNGÜLTIG in XML (undefinierte Entity): -->
<p>Copyright © 2026</p>
<!-- GÜLTIG in XML (numerische Entity funktioniert überall): -->
<p>Copyright © 2026</p>
<!-- GÜLTIG in HTML5 (beides funktioniert): -->
<p>Copyright © 2026</p>
Wenn Sie XHTML oder SVG schreiben, verwenden Sie numerische Entities für alles, was über die grundlegenden 5 hinausgeht, oder verwenden Sie das wörtliche UTF-8-Zeichen direkt.
Best Practices
1. Verwenden Sie UTF-8 im gesamten Stack
Deklarieren Sie UTF-8 überall – in der Datenbank-Kollation, im HTTP-Header Content-Type und im HTML-Tag <meta charset>. Dies macht die Kodierung von Nicht-ASCII-Zeichen mit Entities überflüssig.
<meta charset="UTF-8">
header('Content-Type: text/html; charset=UTF-8');
2. Kodieren Sie kontextgerecht
Unterschiedliche Injektionskontexte erfordern unterschiedliche Maskierungsstrategien:
- HTML-Body: Kodieren Sie
<,>,& - HTML-Attribute: Kodieren Sie
<,>,&,",' - JavaScript-Strings: Verwenden Sie
\uXXXX-Maskierung oder JSON-Kodierung - CSS-Werte: Hier gelten andere Maskierungsregeln
- URLs: Verwenden Sie Prozent-Kodierung (
%3Cstatt<)
Ein für einen Kontext kodiertes Zeichen ist nicht unbedingt in einem anderen sicher.
3. Kodieren Sie bei der Ausgabe, nicht bei der Eingabe
Speichern Sie Rohdaten in Ihrer Datenbank. Kodieren Sie erst bei der Ausgabe in HTML. Wenn Sie bei der Eingabe kodieren, riskieren Sie eine doppelte Kodierung bei der Ausgabe, und die Daten werden in Nicht-HTML-Kontexten (JSON-APIs, Klartext-E-Mails usw.) unbrauchbar.
4. Dekodieren Sie niemals nicht vertrauenswürdige Eingaben vor der Verarbeitung
Das Dekodieren von benutzerseitig bereitgestellten Entities vor der Anwendung von Sicherheitsfiltern macht den Zweck zunichte. <script> dekodiert wird zu <script> – ein klassischer Weg, um naive Filter zu umgehen, die nur spitze Klammern blockieren.
5. Vermeiden Sie doppelte Kodierung
Doppelte Kodierung (&lt;, was als < statt < gerendert wird) ist ein häufiger Fehler, wenn mehrere Anwendungsschichten jeweils unabhängig voneinander kodieren. Zentralisieren Sie Ihre Kodierung in einer einzigen Präsentationsschicht.
6. Denken Sie daran, dass ' nicht in HTML4 enthalten war
Die Entity ' ist in XML und XHTML definiert, war aber in HTML4 nicht definiert. In HTML4-Umgebungen verwenden Sie stattdessen '. HTML5 hat ' offiziell zur Liste der benannten Entities hinzugefügt.
Häufig gestellte Fragen
F: Muss ich jedes Sonderzeichen kodieren oder nur die gefährlichen?
Aus Sicherheitsgründen müssen Sie mindestens die 5 kritischen Zeichen kodieren (< > & " '). Für die Typografie (Copyright-Zeichen, Gedankenstriche, Währungssymbole) ist die Verwendung des wörtlichen UTF-8-Zeichens in einem UTF-8-Dokument völlig in Ordnung. Entities sind in Altsystemen wichtiger oder wenn die Zeichenkodierung nicht garantiert werden kann.
F: Was ist der Unterschied zwischen & und &?
& ist das buchstäbliche Ampersand-Zeichen. & ist seine Darstellung als HTML-Entity. Wenn Sie im HTML-Quellcode ein buchstäbliches & anzeigen möchten, müssen Sie & schreiben. Wenn Sie ein bloßes & vor einem Wort schreiben, könnten Browser versuchen, es als Beginn einer Entity zu interpretieren, was zu einer fehlerhaften Darstellung führt.
F: Warum verhält sich anders als ein normales Leerzeichen?
Ein normales Leerzeichen (U+0020) ist ein umbruchbares Leerzeichen – Browser können Zeilen davor oder danach umbrechen, und mehrere aufeinanderfolgende Leerzeichen werden zu einem zusammengefasst. (geschütztes Leerzeichen, U+00A0) verhindert Zeilenumbrüche zwischen den umgebenden Zeichen und wird nicht zusammengefasst. Nützlich, um Werte wie "100 km" oder "Dr. Schmidt" in einer Zeile zu halten.
F: Kann ich numerische Entities für Emojis verwenden?
Ja. Emojis haben Unicode-Codepunkte und können als numerische Entities dargestellt werden. Das Emoji 😀 (U+1F600) ist 😀 in Hex oder 😀 in Dezimal. In UTF-8-Dokumenten können Sie das Emoji direkt einfügen, aber numerische Entities funktionieren als zuverlässiger Fallback.
F: Welches XSS-Risiko besteht speziell bei href-Attributen?
Das href-Attribut birgt eine einzigartige Gefahr: URLs können das javascript:-Protokoll verwenden. Eine HTML-Kodierung allein reicht hier nicht aus:
<!-- GEFÄHRLICH, obwohl < und > kodiert sind: -->
<a href="javascript:alert(1)">Klick mich</a>
<!-- Sicher: Überprüfen Sie, ob href mit http:// oder https:// beginnt -->
<?php
$url = $_GET['url'];
if (!preg_match('/^https?:\/\//i', $url)) {
$url = '#'; // gefährliche Protokolle ablehnen
}
echo '<a href="' . htmlspecialchars($url) . '">Link</a>';
?>
F: Ist es sicher, innerHTML zu verwenden, wenn ich den Inhalt vorher kodiere?
Wenn Sie alle 5 kritischen Zeichen korrekt kodieren, bevor Sie sie innerHTML zuweisen, ist es im Allgemeinen sicher, einfachen Text einzufügen. textContent ist jedoch einfacher und sicherer. Reservieren Sie innerHTML für Fälle, in denen Sie absichtlich eine kontrollierte HTML-Struktur einfügen möchten.
F: Verarbeiten moderne JavaScript-Frameworks die HTML-Kodierung automatisch?
Ja – React, Vue, Angular und Svelte maskieren die Ausgaben standardmäßig. Reacts JSX maskiert Werte, die mit {} eingefügt werden, automatisch. Jedes bietet jedoch eine explizite Umgehung an (Reacts dangerouslySetInnerHTML, Vues v-html), die mit äußerster Vorsicht und nur bei vertrauenswürdigen Inhalten verwendet werden darf.
Zusammenfassung
HTML-Entities sind ein wesentlicher Mechanismus für:
- Sicherheit — Neutralisierung von
<,>,&,", und', um XSS-Injektionen zu verhindern. - Korrektheit — Sicherstellung, dass Zeichen mit reservierter HTML-Bedeutung wörtlich angezeigt werden.
- Kompatibilität — Darstellung jedes Unicode-Zeichens in Altsystemen oder eingeschränkten Umgebungen.
- Typografie — Zuverlässiges Einfügen von Gedankenstrichen, geschützten Leerzeichen, Währungssymbolen und anderen Sonderzeichen.
In einem modernen UTF-8-Stack müssen Sie primär die 5 sicherheitskritischen Zeichen kodieren, wenn Sie dynamische Inhalte in HTML ausgeben. Benannte Entities wie und — bleiben für die Typografie nützlich. Das Verständnis des Unterschieds zwischen benannten und numerischen Entities sowie der Abweichungen zwischen HTML- und XML-Regeln wird Sie zu einem effektiveren und sicherheitsbewussteren Webentwickler machen.