belun.app Блог
EN

HTML-сущности: когда и зачем экранировать символы

Что такое HTML-сущности, какие символы экранировать, как кодирование защищает от XSS и как кодировать и декодировать их прямо в браузере.

Код на экране с HTML-разметкой — кодирование и декодирование HTML-сущностей онлайн

Когда я впервые сломал страницу неэкранированным <, я минут двадцать смотрел на пустое поле комментария и не мог понять, куда делся текст. Браузер прочитал < как начало тега и молча выкинул всё, что шло после if (x < 10). Ради этого случая HTML-сущности и придумали.

Что такое HTML-сущность

Некоторые символы значат что-то для браузера раньше, чем для читателя. < открывает тег. & начинает сущность. " закрывает значение атрибута. Если вы хотите, чтобы такой символ просто появился на экране, его меняют на код, который браузер выводит буквально.

Форм три:

  • Именованные: &lt;, &amp;, &copy; — читаемые, но набор фиксированный.
  • Десятичные: &#60;, &#38; — номер символа в Unicode.
  • Шестнадцатеричные: &#x3C;, &#x26; — тот же номер в системе с основанием 16.

Все три рисуют одно и то же. &lt;, &#60; и &#x3C; выведут на экран <.

Пять символов, которые пропускать нельзя

В повседневном HTML достаточно помнить про пять символов:

  • &&amp;
  • <&lt;
  • >&gt;
  • "&quot;
  • '&#39;

И здесь важен порядок — на нём спотыкаются чаще всего. Амперсанд экранируют первым. Если сначала заменить < на &lt;, а потом пойти искать одиночные &, вы повторно закодируете только что созданный амперсанд и получите &amp;lt; — на экране будет текст &lt;, а не скобка. HTML-кодировщик обрабатывает амперсанд первым, так что этой ловушки не будет.

Это про безопасность, а не только про отображение

Экранирование — не косметика. Это первая линия обороны от XSS.

Допустим, сайт показывает комментарии. Кто-то вводит в поле <script>fetch('/api/keys')</script>. Если вставить это в страницу как есть, браузер увидит не текст, а тег скрипта — и выполнит его в сессии следующего посетителя, с его куками. Экранируйте < и >, и тот же ввод станет безобидным текстом <script>..., ничего больше.

React и Vue экранируют вывод по умолчанию, поэтому в обычной работе об этом почти не думаешь. Но стоит тронуть innerHTML, собрать HTML-строку руками или писать сырые шаблоны — и страховки больше нет, экранирование снова на вас.

Декодирование и трюк с не-ASCII

Декодирование работает в обратную сторону: вставьте Рыба &amp; чипсы &#8212; £5 и получите Рыба & чипсы — £5. Пригодится, когда читаешь спарсенную страницу, RSS-ленту или ответ API, который пришёл уже закодированным и нечитаемым.

Ещё есть флажок — кодировать всё за пределами обычного ASCII: буквы с акцентами, кириллицу, иероглифы, эмодзи — в числовые сущности вроде &#x1F600; для 😀. Нужен он нечасто. Зато выручает, когда система не переваривает ничего, кроме 7-битного ASCII, а таких старых почтовых шаблонов и полей в древних CMS до сих пор хватает.

И одно скажу прямо: всё считается в браузере. Вставьте конфиг или комментарий клиента, полный разметки, — ни один символ не уйдёт с вашей машины.

Проверьте на своём следующем упрямом фрагменте: HTML-кодировщик и декодировщик кодирует и декодирует в одном поле, мгновенно.

Попробуйте инструмент

HTML-кодировщик / декодировщик →