HTML 实体编码 / 解码器,免费

在特殊字符和 HTML 实体之间互相转换。

没有数据离开您的设备

常用 HTML 实体

字符实体数字说明
&&&和号
<&lt;&#60;小于号
>&gt;&#62;大于号
"&quot;&#34;双引号
'&apos;&#39;单引号
 &nbsp;&#160;不换行空格
©&copy;&#169;版权
®&reg;&#174;注册商标
&trade;&#8482;商标
&euro;&#8364;欧元符号

为什么使用 HTML 实体?

<、> 和 & 等字符在 HTML 中具有特殊含义。如果直接在 HTML 中包含它们,浏览器会将其解释为代码而非内容。将这些字符编码为实体可以避免渲染问题和跨站脚本(XSS)漏洞。

常见问题

命名实体和数字实体有何不同?

命名实体使用描述性名称(&amp;、&copy;),而数字实体使用 Unicode 代码点(&#38;、&#169;)。两者显示效果相同。命名实体更易读,数字实体可用于任何 Unicode 字符。

需要对所有特殊字符进行编码吗?

至少应对 HTML 内容和属性值中的 &、<、> 和 " 进行编码。如果文档使用 UTF-8 编码,现代浏览器可以原生处理大多数其他字符。

三种形式,一个字符

HTML的「实体」(正式称为字符引用):是使用常规ASCII字符序列表示单个字符的转义序列。HTML现行标准定义了三种具体的语法形式:

三种形式在渲染时可互换:&copy;&#169;&#xA9;都产生可见字符©,因为它们都解析为Unicode码位U+00A9。选择哪种形式是源代码可读性的问题,与浏览器行为无关。十六进制往往与已发布的Unicode图表(使用U+XXXX表示法)相匹配,因此&#x2665;更接近官方表示法U+2665,而非&#9829;。数字引用适用于任何Unicode字符,包括星际平面的emoji,&#x1F600;渲染为😀(U+1F600 GRINNING FACE)。

实体存在的原因

三个不同的历史和实际原因:

  1. 转义HTML中具有语法含义的字符。解析器使用某些ASCII字符作为控制符号。<开启标签,>关闭标签,&引入引用,而引号字符分隔属性值。如果您希望这些字符以字面文本形式出现,则必须对其转义。
  2. 表示文档编码中不可用的字符。在UTF-8成为Web通用标准之前(大约在2010年才超过50%),大多数HTML以US-ASCII、ISO-8859-1或Windows-1252格式提供。在这些单字节编码中,©、€、≈或α等字符根本无法用字面字节表示。写&copy;&euro;&#8776;是访问这些码位的唯一方式。
  3. 为不可见或模糊字符表明作者意图。即使在UTF-8页面上,字面的不换行空格(U+00A0)与普通空格在视觉上完全相同,写&nbsp;可以让任何阅读源代码的人明白其意图。

W3C现在建议尽可能使用字面Unicode字符而非实体,「以提高无障碍性和可读性」。对于五个必需转义符,以及真正不可见或模糊的字符,实体仍然有用。

五大转义字符

当您将不可信内容插入HTML时,绝对必须转义的五个字符是<>&"'。OWASP的跨站脚本防御备忘单将这些字符列为最小必需转义集:

字符命名十进制十六进制
<&lt;&#60;&#x3C;
>&gt;&#62;&#x3E;
&&amp;&#38;&#x26;
"&quot;&#34;&#x22;
'&apos; / &#39;&#39;&#x27;

经验法则:每当您将不可信文本放入HTML输出时,先转义这五个字符。不这样做是绝大多数存储型和反射型XSS漏洞的根本原因。

撇号陷阱

&apos;不是HTML 4的一部分,最初仅由XML 1.0定义并继承到XHTML 1.0。Internet Explorer在版本9(2011年发布)之前拒绝将其渲染为',并会显示字面文本&apos;。该实体是专门为HTML5添加的,现在在每款现代浏览器中都是安全的,但为了最大限度的跨浏览器、跨规范兼容性,OWASP和大多数企业级净化库在转义单引号时仍建议输出&#39;而非&apos;,特别是在安全关键代码中。

何时编码,何时不编码

编码决策取决于文本将出现在输出的哪个位置,而非其内容。这是HTML安全中被误解最多的一点。OWASP的指南区分了以下上下文:

每种上下文都有自己的转义规则。混用它们本身就是一个漏洞,例如,将<百分比编码为%3C并不能防止HTML元素上下文中的XSS,在那里%3C只是字面文本%3C

避免双重编码。一个常见的错误是在数据读入系统时转义,再次存储时转义,再次读出时转义,再次渲染时也转义。结果:用户输入了5 < 10,数据库存储了5 &amp;lt; 10,页面渲染出5 &lt; 10而非原始内容。准则是:存储原始Unicode,仅在输出时对特定上下文进行一次编码。

HTML编码与URL编码

两种不同上下文下的两种不同转义系统,经常被混淆:

HTML实体URL/百分比
标准HTML Living StandardRFC 3986
格式&name;&#NN;%HH(十六进制字节)
上下文HTML标记、元素主体和属性URL、查询字符串、表单编码的请求体
空格&nbsp;(不换行),从不使用普通空格%20+
JS函数(解析器处理)encodeURIComponent() / encodeURI()

HTML属性值内的URL会叠加两种转义:先对URL非法字符进行百分比编码,然后对结果URL中的& < > "进行HTML编码。这就是为何href属性内查询字符串中的&号在HTML序列化中变为&amp;

简史

HTML 2.0(RFC 1866,1995年)继承了SGML的实体机制,包含约50个ISO Latin 1的命名实体。HTML 3.2(W3C,1997年1月)添加了数学和符号实体。HTML 4.01(W3C,1999年12月)最终确定了三个实体集(Latin-1、Special和Symbol),共252个命名实体,这也是旧版教程中仍能看到的「252」这一数字的来源。HTML5/WHATWG(现行标准,持续更新)吸收并大幅扩展了表格至2,000余项,主要涵盖MathML和更广泛的Unicode集。XML 1.0(1998年)定义了自己最小的五大实体集(&lt; &gt; &amp; &quot; &apos;),该最小集就是&apos;的起源。

更多问题

在现代代码中,我实际应该使用什么?

生产代码通常不手工编写实体编码,而是调用库。客户端HTML净化使用DOMPurify。Python标准库中的html.escape()。PHP中的htmlspecialchars()。Go中的html/template(默认自动转义)。Java使用OWASP Java Encoder。在React中,写<div>{userInput}</div>会自动转义;名为dangerouslySetInnerHTML的逃生舱口被刻意命名以阻止随意使用。像本页面这样的独立编码器用作健全性检查/调试工具,而非这些库的替代品。

关于电子邮件模板中的标签怎么样?

较旧的电子邮件客户端(尤其是Outlook)将未编码的&解释为格式错误的属性,并可能剥离周围的标记。HTML电子邮件开发者学会了防御性地对每个特殊字符进行实体编码。同样适用于在存储前重写内容的论坛BBCode风格系统;往返过程可能引入意外的字面实体。

JavaScript中的textContent与innerHTML有什么区别?

在原生JavaScript中防止XSS的最重要规则:使用element.textContent = userInput而非element.innerHTML = userInput。设置textContent会将字符串写为字面文本,浏览器在内部处理所有转义。设置innerHTML会将字符串解析为HTML,执行其中包含的任何<script>标签或事件处理属性。如果确实需要标记,请先使用DOMPurify等库进行净化。

编码器能处理emoji吗?

可以,通过数字引用。emoji没有命名实体,它们都使用数字形式。&#x1F600;渲染为😀,&#x2764;&#xFE0F;渲染为红心❤️(心形码位加emoji呈现选择器)。浏览器在内部处理隐式UTF-16代理对转换;您不应手动写代理半项。

有任何内容会发送到服务器吗?

不会。编码和解码是纯函数字符串变换,完全通过JavaScript在浏览器中运行。您的任何输入都不会被上传;页面加载后可离线工作。这一点很重要,因为往返传输测试载荷的云端编码器本身如果托管站点遭到入侵,可能成为XSS攻击向量。

相关工具