HTML 编码解码
在线转换 HTML 实体字符,支持编码与解码,有效防止 XSS 攻击
选择转换方式
什么是 HTML 实体编码?
安全相关结果不能孤立判断,还要结合密钥、使用场景、算法选择和可信来源一起评估。
使用方法
使用方法
- 在左侧输入框中输入或粘贴要转换的文本
- 点击对应的转换按钮选择编码或解码方式
- 结果将自动显示在右侧
- 点击「复制」按钮将结果复制到剪贴板
转换方式
快捷键
- Ctrl + EHTML 实体编码
- Ctrl + DHTML 实体解码
编码技巧
- 将用户可见文本插入 HTML 源码前应先进行编码,特别是文本中可能包含尖括号、引号或 & 符号时。
- HTML 实体编码有助于防止标记被浏览器解析执行,但它只是 XSS 防御的一部分,不能替代上下文输出转义。
使用场景
技术原理
HTML 使用 WHATWG HTML 现行标准定义的两种字符引用。命名字符引用以 & 开头、; 结尾,取自 WHATWG 维护的 entities.json 表(当前规范中约有 2,231 个名称,包括不带尾部分号的旧式别名,如 & 不带 ;)。数字字符引用使用 Unicode 码点,支持十进制 (<) 和十六进制 (<) 两种形式,可编码 U+0000 到 U+10FFFF 范围内的任意字符(代理区 U+D800-U+DFFF 除外)。为保证 HTML 语法安全必须转义的五个字符是 & (&)、< (<)、> (>)、" (") 和 ' (');注意 ' 属于 XML 和 HTML5 但不在 HTML 4.01 中有效,因此 OWASP 建议在双引号分隔的属性中使用数字形式 ',以兼容旧版解析器。 本工具的编码采用单次替换,顺序很关键:& 必须最先转义,否则为 < 和 > 插入的实体前缀本身会被二次转义成 &lt;。解码则利用浏览器的 HTML 解析器,将输入赋值给分离元素的 innerHTML 再读取 textContent;这会调用 HTML 规范中的官方词法分析器状态机(第 13.2.5.72 节字符引用状态到第 13.2.5.80 节),正确解析命名、十进制和十六进制形式,包括缺少分号等格式不规范的输入。完整编码模式的数字编码按码点逐个遍历字符串,使用 String.prototype.codePointAt 处理占用 UTF-16 代理对的增补平面字符(如 emoji U+1F600 变为 😀 而非两个代理引用)。 防范 XSS 需要上下文感知的转义,而不仅仅是 HTML 实体编码。OWASP 跨站脚本防护速查表定义了五种不同上下文:HTML 正文、HTML 属性(带引号与不带引号)、JavaScript 数据(<script> 内)、CSS 和 URL。HTML 实体转义仅覆盖前两种上下文。JavaScript 上下文应使用 \xHH 或 \uHHHH 转义(通过 JSON.stringify),URL 上下文需要 encodeURIComponent(RFC 3986 百分号编码),内联事件处理器则更复杂,因为其值会同时经过 HTML 和 JavaScript 两层解析器。设置 Content-Security-Policy 响应头(script-src 'self' 并移除 'unsafe-inline')是现代纵深防御层,可捕获转义遗漏;而 innerHTML、document.write 和 setAttribute('on*', ...) 等 DOM 操作应替换为 textContent 或框架托管的绑定(React 的 JSX、Vue 的双花括号),它们默认进行转义。
- 命名引用:WHATWG entities.json 中约 2,231 个条目;五个必须转义的名称是 & < > " '(' 仅适用于 HTML5/XML,不适用于 HTML 4.01)
- 数字引用:十进制 &#DDDDD; 和十六进制 &#xHHHH; 覆盖 U+0000 到 U+10FFFF;代理码 U+D800-U+DFFF 和 U+0000 NULL 根据 HTML 规范无效
- 转义顺序:& 必须最先替换,否则后续转义插入的 & 前缀会被二次编码;编码复杂度为 O(n),使用 5 项查找表
- 通过 DOMParser 解码:赋值给分离元素的 innerHTML 会调用 HTML 规范词法分析器(字符引用状态,第 13.2.5.72-80 节),可处理不带尾部分号的旧式实体
- 增补平面字符处理:使用 String.prototype.codePointAt 和 for...of 迭代,使 emoji 和 CJK 扩展 B 区字符(U+10000+)生成单个 &#NNNNN; 而非两个代理引用
- 上下文感知转义(OWASP XSS 防护速查表规则 #0):HTML 正文、HTML 属性、JavaScript、CSS 和 URL 各自需要不同的转义方式;仅靠 HTML 实体无法阻止 JS 或 URL 接收器中的 XSS
- 纵深防御:Content-Security-Policy script-src 'self'(RFC 风格)、DOMPurify 白名单消毒处理富文本输入,以及在原生 DOM 代码中优先使用 textContent/innerText 而非 innerHTML
示例
基础元素编码
输入: <script>alert(1)</script>
输出: <script>alert(1)</script>
用途: 渲染用户提交内容时,避免浏览器把文本当作真实标签解析属性值编码
输入: <div title="Hello & world">
输出: <div title="Hello & world">
说明: 把属性内的引号和 & 转成实体,防止值跳出引号边界在页面中显示 URL
输入: search?q=hello&lang=en
输出: search?q=hello&lang=en
用途: 把 URL 嵌入 HTML 前应先编码 &,否则解析器可能把后续内容当作畸形实体处理非 ASCII 字符(完全编码)
输入: CJK characters like 中文
输出: 完整 UTF-8 数字实体形式 中文(页面支持时也可使用命名实体)
用途: 在老旧 HTML 中安全嵌入任意 Unicode 字符;现代页面通常直接用 UTF-8 编码即可常见问题
HTML 编码会转换哪些字符?
SGML 中保留的五个字符:& → &、< → <、> → >、" → "、' → '(或 ')。可选地,还能把非 ASCII 字符转换成数字实体(&#xNN;),方便对接不支持 UTF-8 的旧系统。
什么时候需要 HTML 编码?
把用户输入的文本插入 HTML 时都需要编码。不编码是 XSS 漏洞的根本原因。HTML 正文、属性值、JavaScript 上下文、CSS 上下文和 URL 上下文都要进行编码——每种上下文的规则略有差别。
' 和 ' 有什么区别?
两者都表示单引号。' 是 HTML5 才加入的,在 HTML4 和老旧邮件客户端中无效——若你的输出会被旧系统解析,请用 '。本工具默认输出 ' 以获得最大兼容性。
为什么编码后的输出里仍然有 &?
如果输入本身就含有 & 这样的实体,再编码就会得到 &amp;——这是正确的,因为输入里的 & 是字面字符,并非实体。如果源数据已经是实体编码,请先解码再处理。
Emoji 会被转换吗?
Emoji 是合法的 Unicode 字符,现代 HTML 把它们当作普通字符处理——除非目标系统坚持只支持 ASCII,否则无需编码。打开“非 ASCII 转数字实体”就能把它们转成 &#xNNNN; 形式。
HTML 编码和 URL 编码是一回事吗?
不是。URL 编码(百分号编码)把不安全字符替换成 %NN,用于 URL;HTML 编码用命名实体或数字实体替换,用于 HTML。要在不同上下文用对应工具,否则会产生双重编码 bug。
转换是在本地完成的吗?
是的。编码和解码都在浏览器中进行,粘贴的文本不会被上传。