ToolBench

开发

HTML 实体编解码

真正要紧的只有五个字符:与号、尖括号、双引号和单引号。在属性值或文本节点里漏掉任何一个,标签结构就会断——而且往往是静默地断,这比直接报错更麻烦。

怎么用

  1. 把文本或 HTML 片段粘贴进来。
  2. 点「编码」转义这五个特殊字符。
  3. 点「解码」把实体还原成普通字符。
  4. 复制结果粘回模板或 CMS 字段。

转义不是过滤

转义是把字符变成「显示出来」而不是「被解释执行」。过滤是删掉你不想要的内容。两者解决不同的问题:把 <script> 转义会让它变成可见文本,这对评论框是对的,对需要接受标记的字段就是错的。混淆这两件事正是大多数 XSS 漏洞的根源——因为一个只挡掉某种写法的过滤器,会放过另外十几种写法。

该转义什么,取决于上下文

在 HTML 文本节点里,要紧的是 < 和 &。在带引号的属性里,引号字符也要紧。在页面内的 JavaScript 字符串里,闭合标签无所谓,反斜杠要紧。在 URL 里,则要改用百分号编码。不存在一个「万能的转义函数」在任何上下文里都正确——这也是模板引擎要替你跟踪上下文,而不是只暴露一个通用辅助函数的原因。

双重转义,以及怎么认出来

页面在本该是 & 的地方显示 &amp;,说明文本被转义了两次:存的时候一次,渲染的时候又一次。解一次得到 &,这是对的;解两次会把本来合法的 &lt; 变成真正的 <——转义就是这样被「解回去」的。

一般原则是:在输出时转义,不要在输入时转义。存原文、在进入 HTML 的那一刻转义,数据在其他地方都还能用;存转义后的文本,则每个使用方都得猜它是不是已经被编码过。

常见问题

会转义哪些字符?

与号、小于号、大于号、双引号和单引号。其余字符(包括中文和带重音的字母)保持原样,因为 UTF-8 本身就能处理。

单引号为什么用数字形式?

数字形式 ' 浏览器和校验器都认。具名实体 ' 在 XHTML 和 HTML5 里合法,但 HTML 4 不支持,输出可能进老模板时数字形式更稳妥。

解码不可信内容安全吗?

解码结果只是放进文本域,不会执行脚本也不会加载图片——因为解析出来的是一个游离元素,从未插入页面。

存数据库前要先转义吗?

不要。存原始文本,渲染时再转义。入库时转义会导致双重转义,输出变成没人看得懂的乱码。

该用命名实体还是数字实体?

有命名实体且被广泛支持的就用命名(&lt;、&nbsp;);ASCII 之外的字符用数字,因为绝大多数字符根本没有命名实体。

&nbsp; 和普通空格一样吗?

不一样。它是不间断空格:会阻止在该处换行,也不会被 HTML 的空白折叠规则压掉。拿它当缩进用,是导致文字选中错乱的常见原因。