Опубликовано: 12 июня 2025 г.
20 мая 2025 года спецификация HTML была обновлена для экранирования <
и >
в атрибутах, что помогло предотвратить уязвимости мутации XSS (mXSS). Это изменение появилось в Chrome 138, который был повышен до бета-версии 28 мая 2025 года и станет стабильной версией 24 июня 2025 года.
В этой статье подробно описывается влияние изменения экранирования атрибутов HTML на веб-разработчиков и возможные сбои; обоснование безопасности этого изменения объясняется в нашей соответствующей статье в блоге Security Engineering.
Что изменилось?
Предположим, что у вас есть элемент <div>
, атрибут data-content
которого имеет значение "<u>hello</u>"
. Что происходит, когда вы читаете div.outerHTML
?
Традиционно вы бы получили следующий HTML:
<div data-content="<u>hello</u>"></div>
После внесения изменений вы получите следующий HTML-код:
<div data-content="<u>hello</u>"></div>
Раньше ни <
ни >
не экранировались в атрибутах. Теперь оба эти символа всегда экранируются.
Что не изменилось
Изменение исключительно изменяет то, как фрагменты HTML преобразуются обратно в строковое представление во время сериализации. Влияние ограничивается сценариями, где осуществляется доступ к свойствам innerHTML
или outerHTML
, или когда метод getHTML()
вызывается для элемента. Эти операции берут существующую структуру DOM и создают текстовое представление HTML.
Это изменение не влияет на парсинг HTML. Рассмотрим следующий HTML:
<div id="div1" data-content="<u>hello</u>"></div>
<div id="div2" data-content="<u>hello</u>"></div>
Оба div
будут проанализированы абсолютно одинаково, и в обоих случаях div.dataset.content
вернет "<u>hello</u>"
.
Что не сломается?
Если вы используете любой DOM API, такой как getAttribute
, getAttributeNS
, dataset
или attributes
, для извлечения значений атрибутов, они вернут те же декодированные значения, что и раньше, в частности, с декодированными <
и >
.
Рассмотрим следующий пример, в котором все строки console.log
будут регистрировать "<u>"
:
<div data-content="<u>"></div>
const div = document.querySelector("div");
// All of the following will log "<u>"
console.log(div.getAttribute("data-content"));
console.log(div.dataset.content);
console.log(div.attributes['data-content'].value);
Что может сломаться?
innerHTML и outerHTML для получения атрибутов
Если вы используете innerHTML
или outerHTML
для извлечения значения атрибута, ваш код может сломаться. Рассмотрим следующий, хотя и немного запутанный, пример:
<div data-content="<u>"></div>
const div = document.querySelector("div");
const content = div.outerHTML.match(/"([^"]+)"/)[1];
console.log(content);
Этот код будет демонстрировать другое поведение после этого изменения. Раньше content
было бы равно "<u>"
, но теперь это "<u>"
.
Обратите внимание, что парсинг HTML с помощью регулярных выражений не рекомендуется . Если вам нужно получить значение атрибута, используйте API DOM, описанные в предыдущих разделах.
Сквозные тесты
Если у вас есть конвейер CI/CD, в котором вы используете Chromium для генерации HTML, и вы написали тесты для сравнения HTML со статическим ожидаемым значением, эти тесты могут перестать работать, если какой-либо атрибут содержит <
или >
.
Это ожидаемая ошибка — вам необходимо обновить ожидаемое значение так, чтобы все символы <
и >
были заменены на <
и >,
соответственно.
Краткое содержание
В этой записи блога описывается изменение в спецификации HTML, которое заставит браузеры начать экранировать <
и >
в атрибутах для повышения безопасности путем предотвращения некоторых случаев мутации XSS.
Изменение будет доступно для всех пользователей 24 июня 2025 года на Chromium (версия 138) и Firefox (версия 140). Оно также включено в Safari 26 Beta, которая должна выйти около сентября 2025 года.
Если вы считаете, что это изменение нарушило работу вашего сайта, и у вас нет простого способа это исправить, сообщите об ошибке по адресу https://issues.chromium.org/ .