Справочник6 мин чтения

HTML-кодирование сущностей и URL-кодирование: ключевые различия

HTML-кодирование сущностей преобразует символы вроде <, >, & и " в HTML-сущности (&lt;, &gt;, &amp;, &quot;) для безопасного отображения на веб-страницах. URL-кодирование преобразует символы в формат %XX для безопасной передачи в URL. Они защищают от разных типов атак и применяются в разных контекстах.

Что такое HTML-кодирование сущностей?

HTML-кодирование сущностей (также называемое HTML-экранированием) преобразует символы, имеющие специальное значение в HTML, в ссылки на сущности, которые браузер отображает как буквальный символ, а не интерпретирует как разметку. Наиболее важные символы для кодирования — это <, >, &, " и '.

Без HTML-кодирования строка вроде <script>alert('XSS')</script> была бы выполнена браузером как JavaScript. После кодирования она превращается в &lt;script&gt;alert(&apos;XSS&apos;)&lt;/script&gt; и отображается как безобидный текст.

HTML-сущности можно записывать в двух формах: именованные сущности, такие как &amp;, &lt; и &quot;, или числовые сущности, такие как &#38;, &#60; и &#34;. Числовые сущности используют кодовую точку Unicode символа и могут представлять любой символ Unicode.

<!-- До HTML-кодирования -->
<p>The formula is: x < y & y > z</p>
<!-- Браузер интерпретирует < как начало тега! -->

<!-- После HTML-кодирования -->
<p>The formula is: x &lt; y &amp; y &gt; z</p>
<!-- Браузер отображает: x < y & y > z -->

<!-- Распространённые HTML-сущности -->
&amp;   → &   (амперсанд)
&lt;    → <   (меньше чем)
&gt;    → >   (больше чем)
&quot;  → "   (двойная кавычка)
&#39;   → '   (одинарная кавычка / апостроф)
&nbsp;  →     (неразрывный пробел)

Что такое URL-кодирование?

URL-кодирование (percent-encoding) преобразует символы, небезопасные в URL, в знак процента, за которым следуют две шестнадцатеричные цифры, представляющие значение байта. Оно определено стандартом RFC 3986 и гарантирует, что URL содержат только допустимые ASCII-символы, которые можно безопасно передавать по интернету.

URL-кодирование необходимо, потому что URL имеют строгий синтаксис, в котором определённые символы служат разделителями (/, ?, &, #, =). Когда эти символы встречаются в данных (например, в значениях параметров запроса), их нужно закодировать, чтобы они не были интерпретированы как структурные элементы.

// Примеры URL-кодирования
space     → %20
&         → %26
=         → %3D
?         → %3F
#         → %23
/         → %2F
+         → %2B

// Полный URL с закодированным параметром запроса
https://example.com/search?q=salt%20%26%20pepper
// Значение q равно "salt & pepper"

Сравнительная таблица

Характеристика HTML-кодирование сущностей URL-кодирование
Назначение Безопасное отображение на HTML-страницах Безопасная передача в URL
Стандарт Спецификация HTML/WHATWG RFC 3986
Формат &name; или &#number; %XX (шестнадцатеричное значение байта)
Пробел становится &nbsp; (неразрывный) или остаётся как есть %20 или +
& становится &amp; %26
< становится &lt; %3C
Предотвращает XSS-атаки, сломанный HTML Сломанные URL, атаки внедрением
Контекст Тело и атрибуты HTML-документа Пути URL, строки запроса, фрагменты
Функция JS Нет встроенной (используйте библиотеку или DOM API) encodeURIComponent()

Когда нужны оба?

Существуют распространённые ситуации, когда требуется и HTML-кодирование, и URL-кодирование. Самый частый случай — когда вы помещаете URL внутрь HTML-атрибута, такого как href или src. Сначала URL нужно правильно закодировать в формате URL, а затем любые специальные HTML-символы в результате должны быть HTML-закодированы.

<!-- Шаг 1: URL-кодирование значения параметра запроса -->
<!-- Значение: "Tom & Jerry" → в URL-кодировке: "Tom%20%26%20Jerry" -->

<!-- Шаг 2: Сборка URL -->
<!-- URL: https://example.com/search?q=Tom%20%26%20Jerry -->

<!-- Шаг 3: HTML-кодирование URL для использования в атрибуте href -->
<a href="https://example.com/search?q=Tom%20%26%20Jerry">
  Search for Tom &amp; Jerry
</a>

<!-- В этом случае последовательности % не нужно HTML-кодировать, -->
<!-- потому что % не является специальным HTML-символом -->

<!-- Но если URL содержит & как разделитель, его ОБЯЗАТЕЛЬНО нужно HTML-кодировать: -->
<a href="https://example.com/search?q=cats&amp;sort=name">
  Search cats sorted by name
</a>
<!-- Без &amp; браузер может интерпретировать &sort как HTML-сущность -->

В современных фреймворках, таких как React, Vue и Angular, HTML-кодирование выполняется автоматически при использовании шаблонных выражений или JSX. Однако URL-кодирование по-прежнему нужно выполнять явно при построении URL из динамических данных.

// React — HTML-кодирование автоматическое, URL-кодирование — нет
function SearchLink({ query }) {
  // URL-кодирование должно быть явным
  const url = '/search?q=' + encodeURIComponent(query);

  // HTML-кодирование в JSX выполняется автоматически
  return <a href={url}>Search for {query}</a>;
  // React автоматически HTML-кодирует и href, и текстовое содержимое
}

Предотвращение XSS: какое кодирование где использовать

Предотвращение межсайтового скриптинга (XSS) требует применения правильного кодирования в зависимости от контекста, куда помещается пользовательский ввод. Использование неверного типа кодирования в конкретном контексте не обеспечивает никакой защиты.

  • Контекст тела HTML: используйте HTML-кодирование сущностей. Это предотвращает интерпретацию внедрённых тегов вроде <script> как разметки.
  • Контекст атрибута HTML: используйте HTML-кодирование сущностей и всегда заключайте значения атрибутов в кавычки. Из атрибутов без кавычек можно вырваться даже при HTML-кодировании.
  • Контекст URL (href, src): используйте URL-кодирование для динамических частей, затем HTML-кодируйте весь URL, если помещаете его в HTML. Проверяйте, что URL начинается с безопасной схемы (https:), чтобы предотвратить javascript:-URL.
  • Контекст JavaScript: используйте экранирование строк JavaScript (JSON.stringify или специализированную библиотеку). Ни HTML-кодирование, ни URL-кодирование недостаточны в контексте JavaScript.
  • Контекст CSS: используйте CSS-экранирование. HTML- и URL-кодирование не защищают от CSS-инъекций.

Ключевой принцип таков: кодируйте под контекст вывода, а не под источник ввода. Один и тот же фрагмент пользовательского ввода может требовать разного кодирования в зависимости от того, где он появляется в ответе. Никогда не полагайтесь только на валидацию ввода для предотвращения XSS; всегда применяйте кодирование вывода.

Похожие статьи

Попробуйте наши бесплатные инструменты