L'échappement HTML remplace la poignée de caractères qui seraient sinon lus comme du balisage par des références d'entités, afin que le texte reste du texte. Petite opération à la réputation démesurée, car la rater est la façon dont survient le cross-site scripting — et parce que « échappez l'entrée » est un conseil subtilement, dangereusement incomplet.
Cinq caractères, et l'ordre dans lequel vous les remplacez
L'ensemble est réduit : & devient &, < devient <, > devient >, " devient " et ' devient '. Tout le reste peut rester tel quel.
Un bug classique se cache dans cette liste. Si vous remplacez les caractères un par un et traitez & en dernier, vous détruisez votre propre travail : < devient <, puis le & que vous venez d'introduire devient &, et la sortie est &lt; — un « < » littéral et visible sur la page au lieu d'un signe inférieur. L'esperluette doit toujours être échappée en premier, car toutes les autres substitutions en introduisent une.
Cet outil contourne entièrement le piège en faisant correspondre les cinq caractères en une seule passe et en remplaçant chacun exactement une fois : la question de l'ordre ne se pose donc jamais. C'est la forme la plus robuste pour ce type de code, et elle vaut d'être copiée : une regex unique avec une table de correspondance ne peut pas doubler l'encodage, là où une chaîne d'appels à replace dépend d'un développeur qui se souvienne d'un invariant.
Pourquoi l'apostrophe est numérique
Regardez de près : l'apostrophe simple devient ' et non ', ce qui paraît incohérent à côté de ". C'est délibéré. ' a été défini en XML et n'a atteint HTML qu'en version 5 — il ne fait pas partie de HTML 4, et de très vieux analyseurs le rendront littéralement comme les quatre caractères ' plutôt que comme une apostrophe.
La référence numérique ' a toujours fonctionné partout. Petite chose, mais du genre qui ressurgit en texte abîmé dans un client de messagerie affichant du HTML de 2003 — et la forme numérique ne coûte rien.
L'échappement dépend du contexte — c'est la partie qui compte
Voici l'idée fausse qui mérite d'être démontée : le « HTML échappé » dans l'abstrait, cela n'existe pas. Il n'existe que du texte échappé correctement pour un endroit précis, et le même échappement, parfaitement sûr à une position, est inutile à une autre.
Entre les balises, échapper ces cinq caractères suffit. Dans un attribut entre guillemets, cela suffit aussi — à condition que l'attribut ait réellement des guillemets. Écrivez <img src=VALEUR> sans eux, et une valeur échappée contenant une espace s'échappe quand même : x onerror=alert(1) ne contient aucun caractère que l'échappement HTML touche, et devient un attribut. Ce sont les guillemets qui font le travail de sécurité, pas l'échappement.
Ailleurs, c'est pire. Dans un bloc <script>, les règles HTML ne s'appliquent pas — il vous faut l'échappement des chaînes JavaScript, et la séquence </script> n'importe où dans un littéral de chaîne termine le bloc quel que soit son entourage. Dans un attribut d'URL, l'échappement HTML ne fait rien contre javascript: comme schéma. Dans un attribut style, CSS a sa propre syntaxe d'échappement. Cinq contextes différents, cinq règles différentes — et un moteur de gabarits qui n'en connaît qu'un produira volontiers un trou.
Décoder est le contraire de la sécurité
Encoder rend le texte inerte. Décoder prend du texte inerte et le remet en vie. Décoder quelque chose puis l'injecter dans une page avec innerHTML défait donc exactement la protection que l'encodage apportait — et c'est un motif réel dans du code réel, généralement écrit par quelqu'un qui pensait que « décoder » voulait dire « nettoyer ».
Cet outil est sûr pour décoder car il ne fait rien du résultat sinon vous le montrer dans une zone de texte, laquelle ne peut rien exécuter. Le risque réside dans ce que vous faites ensuite. Si vous décodez des entités pour insérer le résultat dans une page, utilisez textContent plutôt qu'innerHTML ; et s'il vous faut vraiment afficher du HTML fourni par des utilisateurs, il vous faut un désinfectant comme DOMPurify — une liste blanche de balises et d'attributs sûrs — pas un décodeur d'entités.
Questions fréquentes
Mon texte est-il envoyé à un serveur ?
Non. Cet outil porte la mention « client » : la substitution s'exécute dans votre onglet et rien n'est transmis ni conservé.
Encoder puis décoder me rend-il exactement ce dont je suis parti ?
Oui. Les cinq substitutions sont réversibles et sans ambiguïté : un aller-retour par cet outil restitue le texte d'origine caractère par caractère, esperluettes et guillemets compris. Ce n'est pas vrai de tous les schémas d'échappement, mais c'est vrai de celui-ci.
L'échappement suffit-il à empêcher le XSS ?
Seulement s'il correspond au contexte, comme décrit plus haut. La réponse honnête et courte est que l'échappement manuel est la façon fragile de s'y prendre. Les cadres modernes — React, Vue, Angular, et tout moteur de gabarits serveur actuel — échappent par défaut et savent dans quel contexte ils se trouvent. C'est là la vraie défense. Un outil comme celui-ci sert à inspecter et comprendre une valeur, pas à être la couche de sécurité d'une application.
Et et toutes les autres entités nommées ?
La spécification HTML en définit plus de deux mille, et presque aucune n'est encore nécessaire. Dans un document UTF-8, vous pouvez écrire é, ©, — et 😀 directement, et c'est plus lisible que é, © et — ne l'ont jamais été. Les exceptions à conserver sont les cinq structurelles, plus là où vous voulez précisément une espace insécable. Les entités nommées ailleurs sont une habitude héritée d'une époque où les encodages n'étaient pas fiables.
Pourquoi mon texte encodé affiche-t-il &lt; au lieu de < ?
Quelque chose l'a encodé deux fois. La première passe a transformé < en <, la seconde a vu le & de ce résultat et l'a transformé en &. Cherchez un gabarit qui échappe une valeur déjà échappée en amont — courant quand une couche échappe serviablement et qu'une autre recommence « par sécurité ». Échappez une seule fois, au point de sortie.