Une entité HTML est une manière d’écrire un caractère pour que le navigateur l’affiche comme du texte au lieu de l’interpréter comme du balisage. Tapez un < brut dans votre contenu et le navigateur commence à lire une balise ; écrivez < à la place et il affiche un < littéral sur la page. Cet échange, c’est toute l’idée derrière l’encodage des entités HTML.
Cinq caractères ont une signification particulière en HTML et ce sont ceux que l’on échappe le plus souvent : <, >, &, " et '. On les échappe pour deux raisons. La première est l’affichage : vous voulez montrer du code ou du balisage sous forme de texte. La seconde, et la plus importante, est la sécurité : échapper les entrées non fiables est la base pour stopper le cross-site scripting (XSS).
Il existe trois façons interchangeables d’écrire n’importe quelle entité, nommée (<), décimale (<) et hexadécimale (<), et toutes se résolvent vers le même caractère. La question plus délicate est quand échapper et avec quoi, car la bonne réponse dépend de l’endroit où la valeur atterrit : texte HTML, attribut, script ou URL. Ce guide passe en revue les notations, l’ensemble réservé, une matrice de décision selon le contexte et les pièges qui font le plus trébucher.
Qu’est-ce qu’une entité HTML ? (anatomie)
Une entité HTML, aussi appelée référence de caractère, est un code court qui remplace un seul caractère. Chaque entité commence par une esperluette & et se termine par un point-virgule ;. Ce qui se trouve entre les deux détermine le caractère obtenu.
Il existe trois formes :
&name;— une référence nommée, comme<ou©.&#decimal;— une référence numérique décimale, comme<.&#xhex;— une référence numérique hexadécimale, comme<.
Le navigateur lit la référence, recherche le caractère qu’elle désigne et affiche ce caractère unique. Rien ne change au résultat visible : < et un < brut s’affichent à l’identique. La seule différence, c’est que l’entité est traitée comme du texte, jamais comme le début d’une balise.
Les trois notations : nommée, décimale, hexadécimale
Les trois notations renvoient au même point de code Unicode ; elles ne diffèrent que par l’orthographe. Une entité nommée est la forme lisible, mais elle n’existe que pour les caractères dotés d’un nom défini. Une entité décimale écrit le point de code en base 10. Une entité hexadécimale écrit le même point de code en base 16, ce qui correspond terme à terme à la notation U+XXXX que l’on voit dans le standard Unicode.
| Caractère | Nommée | Décimale | Hex |
|---|---|---|---|
< | < | < | < |
& | & | & | & |
© | © | © | © |
é | é | é | é |
Parce que l’hexadécimal reflète directement U+XXXX (é vaut U+00E9, d’où é), beaucoup de développeurs s’en servent quand ils documentent un point de code précis ou raisonnent à son sujet. Pour le balisage de tous les jours, les entités nommées se lisent le mieux.
Les cinq caractères réservés à échapper impérativement
Ce sont les caractères spéciaux HTML qui modifient la façon dont le navigateur analyse un document. Si l’un d’eux apparaît dans un contenu destiné à être affiché plutôt qu’exécuté, échappez-le.
| Caractère | Nommée | Décimale | Hex | Ce qui casse si vous ne l’échappez pas |
|---|---|---|---|---|
< | < | < | < | Démarre une balise : le navigateur lit le texte suivant comme du balisage |
> | > | > | > | Ferme une balise prématurément |
& | & | & | & | Démarre une entité : la suite peut être lue à tort comme une référence |
" | " | " | " | Termine trop tôt une valeur d’attribut entre guillemets doubles |
' | ' | ' | ' | Termine trop tôt une valeur d’attribut entre apostrophes |
L’entité de l’esperluette HTML est à la racine de tout le système. Le caractère & commence chaque entité, il faut donc l’échapper en premier : échappez les chevrons avant l’esperluette et vous rééchappez le & des entités que vous venez de produire. Plus de détails sur ce piège ci-dessous.
Quand a-t-on vraiment besoin d’échapper ? (selon le contexte)
C’est là que vivent la plupart des bugs et la plupart des vulnérabilités. La règle tient en une phrase : échappez au moment de la sortie, en accord avec le contexte où la valeur atterrit. Une valeur sûre à un endroit est dangereuse à un autre, donc l’encodage appliqué doit correspondre à la destination.
Contenu d’élément HTML
Quand vous insérez une valeur entre des balises (dans un <p>, un <div>, un <td>), échappez <, > et &. Échapper les guillemets ici est inoffensif mais inutile. Si vous voulez afficher le texte <strong> sous forme de caractères littéraux plutôt que de mettre le mot suivant en gras, encodez-le en <strong> et le navigateur imprime la balise au lieu de l’appliquer.
Valeurs d’attribut HTML
À l’intérieur d’un attribut, les guillemets deviennent critiques. Si une valeur figure dans title="…" et contient un " non échappé, elle termine l’attribut trop tôt et permet à un attaquant d’ajouter de nouveaux attributs, un vecteur XSS classique. Échappez " (et idéalement ') en contexte d’attribut. Une valeur comme He said "hi" doit devenir He said "hi" pour rester contenue.
À l’intérieur de <script> ou de JavaScript inline
Les entités HTML n’aident pas ici. Une chaîne intégrée dans un bloc <script> ou dans un gestionnaire d’événement inline a besoin d’un échappement de chaîne JavaScript ou JSON, pas de références de caractères. Écrire " à l’intérieur d’un littéral de chaîne JS produit les six caractères littéraux, pas un guillemet. Pour ce contexte, tournez-vous vers l’outil Échappement JSON, et lisez le guide complet de l’échappement des chaînes JSON pour les règles \uXXXX qui s’appliquent réellement à l’intérieur d’un script.
À l’intérieur d’une URL
Une URL possède son propre schéma d’échappement : le percent-encoding. Les entités HTML ne rendent pas une valeur sûre pour une URL. La chaîne a&b c doit figurer dans une requête sous la forme a%26b%20c, pas a&b c : l’espace casse toujours l’URL, et le & sépare toujours les paramètres. Utilisez l’Encodeur / Décodeur URL pour cela, et le guide d’encodage et de décodage d’URL pour l’ensemble des règles sur les caractères réservés et non réservés.
La matrice de décision
| Contexte | Échapper avec | Exemple | Mauvais choix qui échoue |
|---|---|---|---|
| Contenu d’élément HTML | Entités HTML (< > &) | <strong> → <strong> | Laisser < brut injecte une balise |
| Valeur d’attribut HTML | Entités HTML (" ' critiques) | "hi" → "hi" | Un " non échappé fait sortir du contexte |
<script> / JS inline | Échappement de chaîne JS / JSON | " → \" | Les entités HTML sont inertes en JS |
| URL / chaîne de requête | Percent-encoding | espace → %20 | & et les entités cassent quand même l’URL |
Nommées ou numériques : lesquelles utiliser ?
Les entités nommées sont lisibles et constituent le choix par défaut pour les caractères réservés courants et les symboles bien connus : <, &, ©, —. Elles n’existent toutefois que pour les caractères dotés d’un nom défini. Les entités numériques, décimales ou hexadécimales, peuvent encoder n’importe quel point de code, y compris ceux qui n’ont pas de nom, ce qui en fait le recours universel. Lorsque vous ne pouvez pas garantir que le système consommateur prend en charge une entité nommée donnée, le numérique est le choix sûr.
Pourquoi l’apostrophe est ' et non '
L’entité nommée ' n’a été introduite qu’avec HTML5 et XML. Elle n’est pas définie en HTML4, si bien qu’une poignée d’anciens analyseurs et clients de messagerie l’affichent sous la forme du texte littéral ' au lieu d’une apostrophe. La référence numérique ' (et son jumeau décimal ') désigne exactement le même caractère, U+0027, et est comprise par tout analyseur conforme jamais écrit. Les bibliothèques d’échappement éprouvées comme he émettent ' pour l’apostrophe précisément pour cette raison, et un bon encodeur suit cette convention afin que la sortie puisse être insérée en toute sécurité dans n’importe quel contexte HTML, XML ou d’attribut.
Jeu de caractères ou entités : quand encoder le non-ASCII
Un jeu de caractères, comme UTF-8, décide de la façon dont les caractères sont stockés sous forme d’octets. Une entité est une façon d’écrire un caractère en n’utilisant que de l’ASCII pur (&, #, ;, lettres, chiffres). Ce sont des couches différentes, et les confondre conduit à un encodage superflu.
Sur une page UTF-8 (presque toute page moderne qui déclare <meta charset="utf-8">), les lettres accentuées, les tirets et les emoji sont des caractères bruts valides. Laissez é, — et 😀 exactement tels quels. Tout encoder en entités ne compte que lorsque le texte doit survivre à un jeu de caractères mono-octet hérité ou à un système qui malmène l’UTF-8 brut ; un mode « tout encoder en non-ASCII » existe pour ces cas. Si vous n’êtes pas sûr de la relation entre octets, points de code et caractères, le guide d’encodage UTF-8, UTF-16 et Unicode en expose le modèle.
Pièges courants des entités HTML
Échapper & en dernier provoque un double échappement
L’ordre compte. Si vous remplacez < et > avant &, les entités que vous venez de créer (<, >) voient leur & initial échappé lui aussi, de sorte que < finit en &lt; et s’affiche sous forme du texte littéral <. Échappez toujours & en premier, puis le reste. Cette seule règle évite le bug d’encodage le plus courant qui soit.
Double encodage d’un texte déjà échappé
Repasser dans un encodeur un texte déjà échappé le réencode. & devient &amp;, et le visiteur voit & sur la page au lieu de &. Échappez exactement une fois, au moment de la sortie. Si une valeur traverse plusieurs couches, assurez-vous qu’une seule d’entre elles échappe.
Mojibake lors du décodage
Aller dans l’autre sens a son propre piège. Décodez avec le mauvais jeu de caractères, ou décodez deux fois, et vous obtenez une sortie brouillée : le mojibake classique. Si une page affiche un &lt; littéral là où vous attendiez <, collez-le dans le Décodeur d’entités HTML pour voir exactement ce vers quoi les entités se résolvent ; il gère le nommé, le décimal, l’hexadécimal, et même les références héritées non terminées comme © sans point-virgule final.
Croire que l’échappement guérit complètement le XSS
L’échappement est la première ligne de défense, pas la seule. Comme le HTML comporte plusieurs contextes aux règles différentes, échapper pour le mauvais laisse un trou : guillemets dans les attributs, échappement JS dans les scripts, percent-encoding dans les URL. Associez un échappement correct et adapté au contexte à une Content Security Policy et à l’auto-échappement de votre framework. Voyez l’encodage des entités comme la fondation, avec la CSP et les valeurs par défaut du framework empilées par-dessus.
Comment encoder et décoder des entités en pratique
Quand vous construisez du HTML à la main, vous l’échappez vous-même. Voici une fonction escapeHtml() correcte qui gère l’ordre « & en premier », ainsi que la meilleure pratique pour du vrai code applicatif.
// The five reserved characters and their safe entities:
// < → < > → > & → & " → " ' → '
function escapeHtml(str) {
return str
.replace(/&/g, '&') // & FIRST, so later entities are not double-escaped
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, '''); // numeric form — safe in HTML4, HTML5 and XML
}
const userInput = `<a href="x">Tom & Jerry's</a>`;
const safe = escapeHtml(userInput);
// → <a href="x">Tom & Jerry's</a>
// Better in app code: let the platform escape for you.
// el.textContent = userInput; // the browser escapes; no manual replace
// React / Vue / Angular escape interpolated text by default
// Server templates (Jinja, ERB, Blade) auto-escape unless you opt out
La fonction artisanale est utile pour comprendre ce qui se passe et pour des conversions ponctuelles, mais en production, préférez le chemin intégré. Définir element.textContent laisse le navigateur échapper à votre place, et les frameworks modernes échappent automatiquement les valeurs interpolées. Réservez l’échappement manuel aux cas que la plateforme ne couvre pas.
Pour un travail ponctuel, l’Encodeur d’entités HTML échappe l’ensemble réservé (nommé, décimal ou hexadécimal), et le Décodeur d’entités HTML fait l’inverse. Les deux sont des inverses exacts pour les caractères réservés, vous pouvez donc faire un aller-retour de votre texte dans les deux sans perte.
Foire aux questions
Qu’est-ce qu’une entité HTML ?
Une entité HTML est un code court, commençant par & et finissant par ;, qui représente un seul caractère. Le navigateur affiche le caractère désigné par l’entité au lieu de le traiter comme du balisage. Par exemple, < affiche un < littéral, et & affiche un & littéral.
Quels caractères dois-je échapper en HTML ?
Les cinq caractères spéciaux HTML réservés : <, >, &, " et '. Dans le contenu d’un élément, vous avez surtout besoin de <, > et & ; dans les valeurs d’attribut, les guillemets " et ' deviennent critiques eux aussi. Échappez l’esperluette & en premier afin que les autres entités ne soient pas doublement échappées.
Dois-je utiliser des entités nommées ou numériques (décimales/hex) ?
Utilisez les entités nommées (<, ©) pour la lisibilité avec les caractères courants, car elles sont faciles à reconnaître. Utilisez les entités numériques (décimale < ou hex <) lorsque vous devez encoder un caractère sans nom défini, ou lorsque vous ne pouvez pas garantir que le consommateur prend en charge une entité nommée donnée. Les deux formes renvoient au même point de code.
Les entités HTML protègent-elles contre le XSS ?
Elles en sont la fondation, lorsqu’elles sont appliquées correctement. Échapper les cinq caractères réservés avant de placer une entrée non fiable dans le contenu d’un élément ou d’un attribut HTML stoppe l’injection de balises et de scripts. Mais l’échappement dépend du contexte : les blocs de script ont besoin d’un échappement JavaScript et les URL d’un percent-encoding. Combinez un échappement correct adapté au contexte avec une CSP et l’auto-échappement du framework.
Pourquoi ma page affiche-t-elle &lt; au lieu de < ?
C’est un double échappement. Le texte a été encodé deux fois, ou le & a été échappé après les chevrons, de sorte que le & de < a été transformé en &. Le visiteur voit alors < comme du texte littéral. Échappez exactement une fois et échappez toujours & en premier. L’outil de décodage peut confirmer ce vers quoi les entités se résolvent.
Dois-je échapper des caractères comme é, — ou les emoji ?
En général non. Sur une page qui déclare <meta charset="utf-8">, les lettres accentuées, les tirets et les emoji sont des caractères bruts valides et n’ont besoin d’aucun encodage ; laissez-les tels quels. N’encodez le non-ASCII que lorsque le texte doit passer par un jeu de caractères mono-octet hérité ou par un système qui corrompt l’UTF-8 brut.