跨站脚本攻击(XSS)长期占据 OWASP Top 10 的显著位置,其核心成因是应用程序将不可信数据当作代码执行。防御 XSS 的手段有很多,但最基础、最容易被误解的一环,就是“转义”。很多开发者知道要转义,却分不清 HTML 转义、URL 转义和 JavaScript 转义的适用场景,甚至混用导致防御失效。本文将从 XSS 的常见方式入手,厘清三种转义的本质区别,并给出前端防御的实践建议。
XSS 的常见方式
XSS 通常分为三类:反射型、存储型和 DOM 型。反射型 XSS 发生在服务器将请求参数直接拼接到响应 HTML 中,例如搜索关键词回显;存储型 XSS 则是恶意脚本被持久化到数据库,在帖子、评论、用户资料等位置展示时触发;DOM 型 XSS 不经过服务器,由前端 JavaScript 从 location.hash、document.referrer 等来源取数据并写入 innerHTML 等危险 sink 导致。
无论哪种类型,攻击者最终目的是让浏览器把数据解释为可执行代码。常见的注入点包括:
- HTML 标签之间:
<div>用户输入</div>,可注入<script>或<img onerror>。 - HTML 属性值内:
<input value="用户输入">,可闭合引号后添加事件处理器。 - URL 上下文:
<a href="用户输入">,可注入javascript:伪协议。 - JavaScript 代码块内:
<script>var name = '用户输入';</script>,可闭合字符串执行任意代码。 - CSS 或事件属性中:
style="用户输入",可利用expression()或url()。
正因为注入点上下文不同,单一转义方式无法覆盖所有场景。
三种转义的本质区别
HTML 转义:防御标签与属性注入
HTML 转义的目标是让浏览器把特殊字符当作普通文本,而不是标签或属性边界。需要转义的字符至少包括:
&→&<→<>→>"→"'→'/→/(可选,但推荐)
当数据被插入到 HTML 标签之间或属性值中时,必须使用 HTML 转义。例如:
<div>用户输入</div>
若用户输入 <script>alert(1)</script>,转义后变为 <script>alert(1)</script>,浏览器只会显示文本,不会执行脚本。
需要注意的是,HTML 转义不能用于 URL 或 JavaScript 上下文。如果把 javascript:alert(1) 进行 HTML 转义后放入 href,它仍然是可点击的 javascript: 链接。
URL 转义:防御链接与参数注入
URL 转义(又称百分号编码)用于将字符转换为 %XX 形式,确保数据在 URL 中安全传输。它适用于:
- 将用户输入拼接到
href、src等 URL 属性中。 - 构造查询字符串参数。
- 在 JavaScript 中通过
encodeURIComponent编码后传给后端。
例如,用户输入 javascript:alert(1),如果直接放入 <a href="用户输入">,点击就会执行脚本。正确的做法是先用 encodeURIComponent 编码,或者更严格地校验协议白名单(只允许 http、https、mailto 等)。
但 URL 转义不能替代 HTML 转义。如果 URL 本身要放入 HTML 属性,仍需对 &、" 等字符做 HTML 转义,否则可能突破属性边界。
JavaScript 转义:防御脚本块内的字符串逃逸
当数据需要嵌入 <script> 标签内的 JavaScript 变量时,必须进行 JavaScript 转义。常见做法是将非字母数字字符转换为 \xHH 或 \uHHHH 形式,尤其是引号、反斜杠、换行符和 </script> 序列。
例如:
<script>
var username = "用户输入";
</script>
如果用户输入 "; alert(1); //,不转义就会直接执行。正确的 JavaScript 转义会将其变为 \x22; alert(1); \x2F\x2F,从而保持在字符串内部。
需要特别提醒:不要用 HTML 转义来处理 JavaScript 上下文,因为 " 在 JavaScript 字符串中不会被解析为引号,反而可能造成逻辑错误;也不要用 URL 转义来处理,因为 %22 在 JavaScript 中只是普通字符序列,不能阻止字符串闭合。
前端防御的实践建议
-
根据上下文选择转义方式:HTML 内容用 HTML 转义,URL 属性用 URL 转义,脚本内字符串用 JavaScript 转义。没有一种转义能通吃所有场景。
-
优先使用安全的 API:设置文本用
textContent而非innerHTML;设置属性用setAttribute并配合校验;创建元素用document.createElement。 -
对 URL 做协议白名单校验:不要仅依赖转义,应解析 URL 并只允许
http、https等安全协议,拒绝javascript:、data:等危险协议。 -
启用 CSP:内容安全策略可以作为纵深防御,限制内联脚本和外部脚本来源,即使转义出现疏漏也能降低危害。
-
不要自己写转义函数:使用成熟库,如
DOMPurify处理富文本,he或escape-html处理 HTML 转义,避免遗漏边界字符。
关联安全话题
XSS 防御只是 Web 安全的一环。与之并列的还有 MySQL 防止 SQL 注入的几种写法,核心是使用预处理语句(Prepared Statement)和参数化查询,避免拼接 SQL 字符串;以及 Linux 服务器安全加固清单,包括最小化安装、及时更新补丁、配置防火墙、禁用 root 远程登录、使用密钥认证、开启审计日志等。三者共同构成从应用层到系统层的防御体系。
小结
HTML 转义、URL 转义和 JavaScript 转义不是可互换的工具,而是针对不同注入上下文的专用手段。理解 XSS 的注入点,才能在正确的场景使用正确的转义,并配合安全 API、协议白名单和 CSP,形成有效的纵深防御。安全无小事,转义用对地方,才是防御的第一步。
未经允许不得转载:任鹏个人博客 » XSS 防御中的 HTML 转义、URL 转义与 JavaScript 转义


朋友圈点赞图在线生成源码