2021 年左右,一张 WP Adminify 支持票落地,屏幕截图仍然让我眨眼。一位用户设置了自定义管理员页脚文本 - 一个完全无辜的版权行,带有 a © 以及他们的代理机构的链接。在他们的屏幕上,它呈现为 © 2021 — Bright & Co。三个可见实体,渲染字符为零 罪魁祸首是我 我的保存例程逃过了文本,我的渲染例程再次逃过,介于过滤器之间的某个地方第三次逃过了它,当它击中浏览器时,那个可怜的安培数已经逃过了四次了。
修复花了十分钟。发现它花了两个晚上,因为转义了文本外观 几乎 对了。你撇 © 在数据库转储中,您的大脑会将其自动修复为 ©。我最终把字符串一遍又一遍地粘贴到一个刮擦html文件中,只是为了看看浏览器实际上会在每一层渲染什么。that's是一个悲惨的工作流程,而它's正是为什么html实体编码器解码器是我内置到toolz。dev中的第一个工具。
同一枚硬币的另一面更可怕,在那张票证的前几个月,在对自己的插件进行代码审查时,我发现了一个设置字段,该字段将用户输入回显到管理员通知中,而没有 esc_html()。任何有权访问该字段的人都可以存储 <script> 并让它为每个加载页面的管理员执行。存储 XSS,在我自己的代码中,缺少一个函数调用。没有人利用它 - 我很幸运。但它永久地改变了我对逃避的看法:它's 不是格式化杂务,它's "text"和"code。"之间的边界
So this guide cover both directions。encoding, so untrusted text stays text。Decoding, so you can read what some over-eager pipeline mangled。and equence theory - named vs numeric references, the five character that actually matter, why order of operations causes double-escape - that you can debug this stuff receiving。
TL;博士: 将您的文本粘贴到 Toolz.dev HTML 实体编码器/解码器 要在任一方向的原始字符和实体之间进行转换 - 名称、十进制或十六进制。它运行 100% 客户端,因此用户内容和 PII 永远不会离开您的浏览器。经验法则:始终逃避五种特殊功能(
& < > " ')在不可信输入中,并进行编码&先还是你'll双逃。
主要特点
在两个方向上编码和解码
我需要转身的时间的一半 <script> 进入 <script> so它显示为博文中的文字另一半 I'm 走反了- 转个刮 &#8217;s back into a readable a postrope。the 工具处理两者。粘贴文本, 挑选编码或解码, 完成。没有模式狩猎, 没有单独的工具为每个方向。那听起来微不足道直到你've 使用工具, 只解码, 你发现自己打开第二个选项卡, 为你的docs编码代码样本。往返也是一种很好的理智检查:编码, 解码,并确认你拿回了原来的字符串。如果你不't, 你的输入中的某些东西已经部分转义- 这本身就是有用的信息。
名为实体:&amp;,&lt;,&复制;和朋友
命名的角色参考是人类可读的- & 为&, < 为<, © 为©, — 为em-dash。工具携带一个147个名字的策划表,而不仅仅是著名的五个:排版(排版) 、 …、 ’、 “),货币,数学和箭头,希腊字母,完整的拉丁-1重音范围,以及一些像卡片套装这样的赔率。那个范围是现实世界内容实际需要的 - WordPress 释放 、 …、和 ’ 通过不断地进行 wptexturize,解码器只知道十几个名字,你的文本中有一半散布着未解决的参考文献。
明确 147 不是什么: WHATWG HTML Standard定义了超过2200个命名引用,所以这是一个实用的子集而不是完整的表,如果一个名字是't在里面,解码让引用保持不变而不是猜测- &bogus; 出为 &bogus;。编码具有互补的行为,它's更有用的一半:任何字符 没有 表中的名称会自动回落到十进制数字引用,因此不会默默地删除任何内容。表情符号编码为 🌍,中文文本为 你好。存在的名称,其他地方的数字。
与值得了解的浏览器行为的又一个分歧:解码器区分大小写,需要分号,浏览器会解决 © 甚至是赤裸裸的 & 由于旧的兼容性规则,在某些解析上下文中没有尾随分号;该解码器既不能解决问题。实际上,'很好 - 任何现代工具 生成 是小写和终止的 - 但如果你'重新解码从一个古老的CMS中抓取的HTML,那's边缘你'll击中。
数字参考:十进制和十六进制
任何 统一码 字符可以写成数字字符参考 - 类似十进制 — 或者像十六进制 — (两者都是em-dash),解码器解析两种形式,这是标准中没有名字的字符的转义舱口,而它's你'll在api响应和rss提要中不断相遇的形式,其中 ’ (右单引号)实际上是一个签名, Hex 引用直接映射到 Unicode 代码点 - U+2014 是 —-这就是为什么我更喜欢它们时I'm交叉引用与Unicode图表。
诚实的限制,因为您'将在使用工具后一分钟内注意到它:数字 编码 mode只发出十进制,有's没有十六进制输出选项解码 — works fine; 要求编码器生产它 does't。两种形式在语义上与每个浏览器相同,所以这在功能上不会花费你任何费用,但如果你的代码库在十六进制上标准化你'将手工转换。it's在我的列表中。范围外的引用被抓住而不是被破坏- � unicode最大值之上,并返回一个显式错误而不是替换字符。
完整的 Unicode 覆盖范围
Emoji,CJK字符,阿拉伯语,结合变音符号,作品,如果有代码点,工具可以将其表达为一个实体并解决回来,这比你更重要'd为本地化工作思考-I've调试了德国umlauts到达as ü 来自一家翻译供应商,作为原始 UTF-8 ü from another,在同一个导入文件中。latin-1之外窒息的工具对此毫无用处。U+FFFF(emoji live up there)上方的字符作为单个代码点被正确处理,而不是被破坏的代理对。
解开双转义文本
的 &amp; 题。当两层管道都逃逸时, & 变成 &amp;- 三层给你 &amp;amp;.解码一次恰好剥离一层,这样就可以反复运行解码器,看着洋葱解包: &amp;amp; → &amp; → & → &。计算通行证告诉你堆栈有多少层正在逃逸,这正是我在那四次逃逸的WP Adminify页脚错误期间需要的诊断。每层一个解码。It's我知道的最快方法来定位管道中的哪个位置发生额外的逃逸。
具有字符计数的并排窗格
左边的输入,右边的输出,字符在两者之上都很重要。那个计数对的工作量比听起来还要多:escaping 是一个扩展操作,所以如果你编码 40 个字符并拿回 44 个字符,恰好触摸了一个特殊字符。当 I'm 审核模板是否已经逃脱了某些东西时,delta 在 I've 读取输出的一个字符之前告诉我。Encode、Decode、Swap 和 Clear 是按钮 - 那里's 没有即兴转换,I'll 承认这是一个故意的权衡,我有时会后悔。显式操作意味着你总是知道哪个方向产生了文本你're 看,而逃脱的错误则模糊性是整个问题。但对于探索性戳,按键驱动版本确实会更好。
100% 客户端 - 无上传
Everything都在你的浏览器里运行,没有请求,没有服务器,没有日志,这是't a nice-to-have:你're escape 的文本通常正是你应该的文本't 粘贴到随机的网站中- 用户生成的真实姓名评论,带有客户地址的电子邮件模板,支持票证内容。I've 之前写过为什么这很重要 我们的数据隐私指南;简短的版本是,上传输入的转换器是您从未审查过的数据处理器。 Toolz.dev 实体工具 1次加载就离线工作,飞机模式是有效的测试- 试试。
HTML实体编码器和解码器的使用方法
1步:打开工具并粘贴您的文本
去 Toolz.dev/tools/html-entities and paste your input - 一个代码片段,一个被破坏的RSS摘录,一个电子邮件模板片段,不管怎样。那里's没有大小上限值得担心的正常使用;I've粘贴了整个渲染的插件更改日志。由于处理是客户端,敏感内容在这里没问题。
第 2 步:选择编码或解码
编码将原始字符变成实体(< → <) - 当你想要标记显示为文本时使用它。解码将实体解析回字符(& → &) - 当你're阅读转义内容时使用,如果你'不确定你的文本处于哪种状态,先解码,看看有什么变化,不变输出就已经是平淡无奇了。
3步:选择参考样式(编码时)
模式下拉恰好有三个选项,选择比看起来更重要。 名字 对所有它有名称的东西进行编码,其余的则回落为十进制 - 在源和差异中可读,但它也逃脱了 ©、 —、 é 以及所有其他非 ASCII 字符,如果您'无论如何,这会使输出膨胀。在 UTF-8 上。 数字 以纯十进制进行相同的覆盖。 仅限特殊字符 触及什么,但 & < > " ' 并将您的口音、em-dashes 和表情符号保留为原始 UTF-8 - 这是我用于真实内容的模式,它's 匹配什么的模式 htmlspecialchars() 在 PHP 中确实如此。请注意 ' 总是以 ',从来没有 ',在所有三种模式中;那'的刻意,自 ' HTML 4中未定义,并且旧的电子邮件客户端仍然会对其窒息。
4步:检查输出,然后复制
Hit Encode 或解码,然后读取右侧窗格,对于解码作业,请专门查找剩余部分 & sequences - a survivor 表示文本是双转的,所以点击 Swap 再次解码,当它读取干净时,将结果复制到您的模板、CMS 或代码中,对于重复作业,往返一次(编码然后解码)以确认没有发生任何有损;使用仅限特殊字符的模式,往返是精确的。
名字与数字实体 - 以及真正重要的五个字符
Let's 直截了当的术语,因为"HTML 实体"被松散地使用。WHATWG HTML 标准 - 定义浏览器实际如何解析 HTML 的活规范 - 指定了一个表 命名字符引用:超过 2,200 个名字,例如 、 —、 …、 →、每个映射到一两个 Unicode 代码点。单独地, 数字字符参考 让您直接寻址任何代码点:小数 (—)或十六进制(—)。相同的 em-dash,三个拼写。
Here's我固执己见的看法,通过多年的WordPress工作而变得更加尖锐: 在这 2,200 多个名字中,只有 5 个字符实际上对正确性和安全性很重要。 其他一切都是排版,在 UTF-8 页面上 - 这是您应该在 2026 年发货的每个页面 - 您只需键入真实字符即可。你不需要't需要 —;你需要-。重要的五位是HTML中有句法意义的:
| 角色 | 实体 | 为什么这很重要 |
|---|---|---|
& |
& |
启动每个实体 - 逃脱角色本身 |
< |
< |
打开标签 |
> |
> |
关闭标签 |
" |
" |
划定双引号属性 |
' |
' |
定义单引用的属性 |
注意最后一行: '不是 '.名字 ' HTML5中有效,但它曾是HTML4的n't部分,而旧的工具(和旧的电子邮件客户端 - 更多关于后来的那些)可以在上面跳闸数字表单到处都有效,这是一种迂腐,可以为您节省一个令人困惑的错误报告。
操作顺序是整个游戏。 编码时, & 必须逃脱 第一。如果你逃跑了 < 到 < 然后逃逸的安培数,你'll将自己的输出转换成 &lt;-恭喜你've双逃,解码就是镜像: & 必须解决 最后、或者 &lt; 变成 < 变成 < and you've未被解码(或者更糟糕的是,从故意转义的文本中重新引入了实时标记)几乎每个手卷转义错误I've评论 - 包括我自己的 - 都是订购错误。
上下文很重要,这就是逃跑与安全相遇的地方。 OWASP跨站脚本预防速查表对此直言不讳:HTML实体编码是HTML的正确防御 身体 並 属性 上下文,但确实如此 不是 javascript 字符串、URL 或 CSS 就足够了。 < a 的内部 <script> block does't解码-脚本内容是't解析给实体-所以实体编码在那里没有什么好用的,每个上下文都需要自己的编码器:实体编码对于HTML, \uXXXX JS字符串的转义,URL的百分比编码(that's what our) URL编码器/解码器 是(用于)。在错误的上下文中使用正确的编码器是看似消毒的代码保持可利用的经典方式。
PHP 方面,知道你的两个功能。 htmlspecialchars() 仅逃脱五个特价(通过) ENT_QUOTES 或者你错过了单句话--真正的混蛋)。 htmlentities() 逃脱 一切 它有一个指定的实体,转动 ü 进入 ü。在UTF-8页面上, htmlentities() 是几乎总是错误的选择;它会膨胀输出,并在字符集被错误声明时破坏内容wordpress明智地包装了这一点:
echo esc_html( $footer_text ); // body context
echo '<a title="' . esc_attr( $title ) . '">'; // attribute context
esc_html() 並 esc_attr() 2个都逃脱了五个特殊与正确的标志,选择了每个上下文 - 恰好是后期逃脱纪律OWASP规定。规则我钻到每个代码审查:逃脱在输出时间,在输出's上下文,恰好一次。
这让它回家了:有了 UTF-8,你就很少了 需要 stypographic字符的实体,你需要它们作为标记显着字符和不可信输入,其他一切都是遗留习惯。
常见用例
在博客文章和文档中显示代码片段
编写包含以下内容的教程 <script> 或 <?php 并将其粘贴到 CMS raw 中,浏览器将尝试这样做 执行或吞咽 your 示例而不是显示它。HTML上下文中的每个代码示例都需要 <、 >、和 & encoded。ime 不断地这样做插件文档 - readme HTML,知识库文章,内联示例在管理 UI 帮助选项卡中。工作流程:编写片段,通过运行它 实体编码器的,把逃过来的版本粘贴进去 <pre><code>.三十秒,还有你的 <script> 显示为 <script> dom中消失而不是消失如果你're建立docs工作流程一般来说,我们的 编码工具指南 覆盖工具箱的其余部分。
从数据库和提要中清理双转义文本
的 &amp; plague。save上一个cms转义,一个插件转义,一个缓存层有帮助地再次转义时,它就会出现。我曾经发过一个wp管理更改日志,其中wordpress。org readme解析器和我自己的构建脚本对于谁转义存在分歧- 渲染的更改日志有23个可见 &S在用户给我发电子邮件之前。RSS提要更糟糕;提要内容经常被转义HTML 里面 XML,所以消费者通常会对其进行过度解码或欠解码,修复的是诊断解码:粘贴坏掉的文本,一次解码一次,计算多少次通过,直到它's clean。that count等于转义层数- 现在你确切地知道你的管道中有多少块在触摸文本,你可以找到多余的。
安全地准备用户生成的内容
Comments, review text, profile bios, support tickets - 任何用户输入的东西都是不可信的,而且它经常包含PII:真实姓名,电子邮件,地址这里有两个担忧相互碰撞,首先,安全性:该内容必须在输出处进行实体编码或者您're one <img onerror=...> 离存储的xss(问我差点发货的设置字段) 二、隐私:当你're调试 为什么 a特定用户's bio打破你的布局,你're处理他们的个人数据-粘贴到服务器端转换器意味着将PII运送到第三方,toolz。dev工具在本地处理所有内容,因此测试真正的问题字符串是安全的,对样本进行编码,检查你的模板是什么 应该 已经生产,与它确实生产的东西不同。
电子邮件 HTML 模板
Email HTML是Web开发,具有20年的渲染引擎,有些客户端处理原始UTF-8罚款;其他-取决于你的ESP如何设置传输编码-将排版字符装入mojibake防御性约定许多电子邮件开发人员仍然遵循:将非ASCII排版编码为实体()—、 ’、 为间隔黑客),因此线上的字节是纯ASCII。并记住 ' 超过 '- Outlook's较旧的引擎正是从未学习过HTML5名称的工具,由于模板通过客户名和地址进行个性化设置,这又是内容I'd只通过客户端工具对模板chrome进行一次编码,保持合并字段为原始字段,在合并时间转义它们。
解码抓取的内容和 API 响应
刮一页或消耗一个草率的 API,你'就会淹没 ’、 “、 &、和 。一些 API 在 JSON 内返回实体编码的字符串 - 这种格式根本不需要 HTML 转义 - 因此您可以获得诸如以下的工件 "title": "Fish & Chips"。在那个数据进入你自己的数据库之前,解码一下,清理一下UTF-8;存储规范文本,输出时转义,我在将内容导入到Laravel app时不断打这个:先解码实体, 然后 漂亮打印并检查有效负载 json格式化程序。以其他顺序执行它意味着读取每个撇号长为七个字符的 JSON。如果有效负载以 base64 为基础 - 包裹在其之上 - 一些 Webhook 提供商这样做 - Base64 转换器 处理外层,我们的 Base64 编码指南 解释为什么存在这种包装。
使用特殊字符本地化内容
翻译文件以每个可以想象的状态到达。一个供应商发送干净的 UTF-8 ü;另一个发送 ü;第三个发送 ü;偶尔你在一个PO文件中得到所有三个,导入之前,我用解码通行证将所有内容标准化为原始UTF-8 - 规范存储,一致搜索,sane diffs。RTL标点符号,CJK括号,以及发货字符串中的重音拉丁语,同样适用于导入时解码,存储真实字符,让您的输出层仅逃脱五个特价,您的翻译人员也会感谢您: über 这不是任何人都应该校对的词。
名称 vs 十进制 vs 十六进制 vs 原始 UTF-8:您应该使用哪个?
| 形式 | 例(电磨盘) | 可读性 | 浏览器支持 | 何时使用 |
|---|---|---|---|---|
| 名称实体 | — |
好--自我描述 | HTML4 时代名称的通用;仅 HTML5 名称(例如 ') 旧工具中的失败 |
五个特别节目;电子邮件 HTML 等遗留上下文 |
| 小数参考 | — |
差 - it's一个数字 | 通用,包括古代解析器 | 没有名字的字符;最大兼容性转义(') |
| 六角参考 | — |
差,但映射到 Unicode 代码点 | 在任何遥远的现代事物中都具有普遍性 | 当交叉引用 Unicode 图表或规范时 |
| 原始 UTF-8 | — |
完美 | 通用于正确声明的 UTF-8 页 | 一切都打印 - 这应该是您的默认值 |
我的立场是: 编写用于排版的原始 UTF-8、五个特价的储备实体和不受信任的输入。 一份充满的文件 — 並 … 是无人能校对的文档,它发出信号,自2008年以来,它一直信任其字符集声明的工作流现代堆栈 - WordPress,Laravel,Next。js,您'd今天选择的每个数据库 - 是UTF-8端到端键入真实字符。
实体赚取其保留的地方: &、 <、 >、 "、和 ' 为任何可以解释为标记的东西,总是,没有例外,在输出时间应用。并且在敌对渲染环境中 - 电子邮件客户端,未知解析器消耗的提要 - 数字引用是偏执但合理的选择,因为它们早于每个兼容性参数之间的十进制和十六进制,它's味道;我倾向于十六进制,因为 — 配U + 2014,我可以停止在脑海中进行基础转换。
常见问题
HTML实体是什么?
HTML实体是一个文本序列,它表示一个字符,而不是直接写字符。它以一个安培数开始,以分号结束。有命名引用,如&和©,以及数字引用,如©(十进制)或©(十六进制),指向Unicode代码点。浏览器在解析时解析它们,因此<显示为小于号而不是打开标签。它们的存在是为了让你可以显示否则会被解释为标记的字符。
HTML中必须转义哪些字符?
五: &、小于、大于、双引号、单引号- 写成&、<、>、"、'。&和,因为它启动实体;角度括号,因为它们定义标签;引号,因为它们定义属性值。在元素正文中,你只需前三个就可以逃脱,但到处逃脱所有五个是永远不会咬你的习惯。其他一切 - 重音、破折号、表情符号 - 可以在正确声明的页面上为原始 UTF-8。
<写成命名实体与<有什么区别?
Nothing,一旦浏览器解析它们- 都会产生一个小于号,命名形式是WHATWG标准中的查找's命名引用表;<直接地址Unicode代码点60,而<是同一个代码点在十六进制命名实体更容易被人类读取;数字引用适用于所有字符,包括数千个没有名字的常见特价,选择你的团队发现哪个更易读- 浏览器不在乎。
为什么我的页面显示&amp;而不是一个安培数?
Double escaping。你的堆栈的某一层逃脱了一个已经逃脱的字符串,将&变成&amp;浏览器解码一个级别,显示剩下的,它通常意味着两个组件都认为逃脱是他们的工作- save上的CMS加上render上的模板是经典的一对字符串,在解码器中一次通过一次解码;直到读取干净的通过次数等于逃脱它的层数。然后让恰好一层负责,在输出时间。
转义 HTML 会阻止 XSS 吗?
HTML正文和属性上下文中,是的-实体编码不可信输入有核心防御,因为有效负载呈现为惰性文本。但并非处处都足够。OWASP XSS Prevention 速查表明确指出 JavaScript 字符串、URL 和 CSS 各自需要自己的上下文特定编码;脚本块内的实体编码不会在输出处逃逸,在您要输出的上下文中,使用该上下文's 编码器。实体编码是该套件中的一种工具,而不是整个套件。
PHP 中 htmlspecialchars 和 htmlentities 有什么区别?
htmlspecialchars()只逃避标记-显着字符-并且你应该通过ent_quotes,所以它涵盖了单个引用。htmlentities()转换每个具有命名实体的字符,因此重音字母成为像uuml引用这样的东西。在utf-8页面上,htmlspecialchars()几乎总是你想要的;htmlentities()在字符集错误配置时会膨胀输出并导致mojibake。wordpress开发人员大多通过使用esc_html()和esc_attr()来避免该问题,这些字符在每个上下文中应用右侧标志。
我应该使用 apos 命名的实体来进行撇号吗?
Prefer '。apos名称在HTML5中是有效的,但从来不是HTML4的一部分,所以较旧的解析器- 包括一些电子邮件客户端内部的渲染引擎- 无法识别它,并且会按字面显示数字形式'意味着相同的字符,适用于所有发货过的东西。它是一个丑陋但安全的选择,这通常是逃逸的正确权衡。如果您知道您的输出只会击中现代浏览器,则apos很好;电子邮件模板正是您无法知道的地方。
将用户数据粘贴到在线实体转换器中安全吗?
仅当工具在浏览器中处理文本时。用户生成的内容和电子邮件模板通常包含名称、电子邮件和其他 PII,并且将输入发布到服务器的转换器刚刚收到该数据,但未达成一致。toolz。dev HTML Entities Encoder/Decoder 运行 100% 客户端 - 无需上传、无日志记录,并且一旦页面加载后它就会离线工作。如果您无法验证工具如何处理输入,请勿将生产数据粘贴到其中。
逃脱一次,在正确的地方
10年我逃避错误中拿一个东西,拿这个:恰好你堆栈的一层应该逃避,应该是输出层 存放干净的UTF-8 在渲染时间逃避五种特价,在上下文中你'把渲染变成每一个 &amp; in production 是两个组件争夺那份工作的地图 - 而每一个未逃脱的用户字符串都是一个存储的 XSS,等待一个可能不会发生的代码审查 我的几乎没't。
保持 HTML 实体编码器/解码器 在您的调试轮换中与其兄弟姐妹一起 - URL编码器/解码器 对于百分比编码上下文(the URL编码指南 走过 %2520的,百分编码表亲 &amp;),the Base64 转换器 对于包裹的有效载荷,以及 箱转换器 对于它们之间的标识符重命名 grunt 工作。 编码工具指南 走整套。
由于您调试的字符串经常是某人'的实际名称或电子邮件:上面的所有内容都运行客户端,没有任何上传,可以在您的网络选项卡中验证。那'不是营销 - 它'是我以我的方式构建这些工具的原因。更多关于这一理念 数据隐私指南。



