HTML 规范变更:对属性中的 < 和 > 进行转义

2025 年 5 月 20 日,HTML 规范更新,以转义属性中的 < 和 >,有助于防范突变 XSS (mXSS) 漏洞。此变更已应用于 Chrome 138,该版本已于 2025 年 5 月 28 日升级为 Beta 版,并将于 2025 年 6 月 24 日升级为稳定版。

本文详细介绍了 HTML 属性转义变更对 Web 开发者的影响以及可能出现的破坏情况;安全工程博客上的相关博文介绍了此次变更背后的安全原理。

有何变化

假设您有一个 <div> 元素,其属性 data-content 的值为 "<u>hello</u>"。读取 div.outerHTML 后会发生什么?

以前,您会收到以下 HTML:

<div data-content="<u>hello</u>"></div>

更改后,您将获得以下 HTML:

<div data-content="&lt;u&gt;hello&lt;/u&gt;"></div>

以前,属性中不会对 < 或 > 进行转义。现在,这两个字符始终会进行转义。

未改动的地方

元素周期表此更改仅修改了在序列化过程中将 HTML 片段转换回字符串表示的方式。影响仅限于访问 innerHTML 或 outerHTML 属性或对元素调用 getHTML() 方法的情况。这些操作会采用现有的 DOM 结构,并生成文本 HTML 表示法。

此更改不会影响 HTML 解析。请考虑以下 HTML:

<div id="div1" data-content="<u>hello</u>"></div>
<div id="div2" data-content="&lt;u&gt;hello&lt;/u&gt;"></div>

这两个 div 将以完全相同的方式解析,在这两种情况下,div.dataset.content 都会返回 "<u>hello</u>"

哪些内容不会中断?

如果您使用任何 DOM API(例如 getAttributegetAttributeNSdataset 或 attributes)检索属性值,它们将返回与之前相同的解码值,尤其是在解码了 < 和 > 的情况下。

请考虑以下示例,其中所有 console.log 行都会记录 "<u>"

<div data-content="&lt;u&gt;"></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 = div.querySelector("div");
const content = div.outerHTML.match(/"([^"]+)"/)[1];
console.log(content);

此代码在发生此更改后将表现出不同的行为。以前,content 等于 "<u>",但现在等于 "&lt;u&gt;"

请注意,不建议使用正则表达式解析 HTML。如果您需要获取某个属性的值,请使用前面部分介绍的 DOM API。

端到端测试

如果您有一个 CI/CD 流水线,其中使用 Chromium 生成 HTML,并且您编写了测试来将 HTML 与静态预期值进行比较,那么如果任何属性包含 < 或 >,这些测试可能会中断。

这是预期的破坏情况 – 您需要更新预期值,以便将所有 < 和 > 字符分别转义为 &lt; 和 &gt;,

摘要

这篇博文介绍了 HTML 规范中的一项变更,该变更将导致浏览器开始对属性中的 < 和 > 进行转义,以通过防止某些突变 XSS 实例来提高安全性。

自 2025 年 6 月 24 日起,所有使用 Chromium(版本 138)和 Firefox(版本 140)的用户均可使用此更改。它也包含在 Safari 26 Beta 版中,该版本应该会在 2025 年 9 月左右发布。

如果您认为此更改破坏了您的网站,并且您无法轻松解决此问题,请访问 https://issues.chromium.org/ 提交 bug。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注