html解析器不执行js,但通过状态机决定字符如何被解析为标签、属性或文本;攻击者利用其容错机制(如闭合引号、注释逃逸、非法语法修复)使过滤失效,最终让恶意代码进入dom并触发执行。

HTML解析器如何把用户输入变成可执行代码
HTML解析器本身不“执行”JavaScript,但它决定哪些字符被当作标签、属性、文本或注释来处理。一旦攻击者能控制解析器的状态机走向,比如在属性值里闭合引号、在注释中逃逸、或利用浏览器对非法语法的容错(如<img>被解析为<img src="x">),就可能让本该被转义的内容绕过过滤,最终进入DOM并触发事件。关键不是“有没有过滤”,而是“过滤发生在哪个解析阶段之后”。
常见绕过路径:注释、大小写、编码嵌套、标签混淆
很多过滤逻辑只匹配明文关键词,而HTML解析器会在多个阶段解码。例如:
- 服务端用
htmlspecialchars()转义了和<code>>,但前端JS又用innerHTML插入一段含<script>的字符串 → 浏览器先HTML解码再解析,结果还原成<script></script> - 过滤器禁用
onerror,但没拦ONERROR或oNerrOr→ 某些旧版IE或配置宽松的解析器仍会触发 - 在
<svg></svg>内使用<title></title>→<title></title>是合法标签,但onload在SVG上下文中仍有效 - 用
<!--><script>alert(1)</script>绕过基于正则的“开头必须是<”检测 → 注释结束符-->后紧跟标签,部分解析器不校验注释嵌套
怎么验证某个输入点是否真被解析器“放行”
不要只看源码里有没有escapeHtml调用,要观察它是否覆盖所有输出路径:
- 打开开发者工具,在Network面板里找到返回用户数据的XHR响应,确认原始响应体是否已含未转义的尖括号或事件属性
- 在Elements面板里右键目标节点 → “Edit as HTML”,手动插入
<img src="x" onerror="alert(1)">→ 如果弹窗,说明DOM已可执行,过滤完全失效 - 检查是否存在
v-pre、data-ignore、ng-non-bindable等跳过框架解析的指令,这些区域内的用户输入直接进DOM - 富文本场景下,查看Markdown解析后生成的HTML是否走同一套净化流程;若直接
dangerouslySetInnerHTML或v-html渲染,那前面所有服务端转义都白费
最常被忽略的解析上下文:style、URL、JS字符串
同一个用户输入,插入位置不同,解析规则天差地别:
- 插在
style="..."里:需防CSS表达式、url(javascript:...)、@import注入 - 插在
href="..."或src="..."里:协议白名单必须严格,javascript:、data:text/html、vbscript:全得拒掉 - 插在
onclick="..."这种JS执行上下文中:不能只HTML转义,得用JS字符串转义(如\x3c代替),否则<code>onclick="alert('<script>')"</script>照样执行 - 插在
location.href = "..."里:本质是JS字符串,但若拼接时用了encodeURI()而非encodeURIComponent(),斜杠/冒号可能未被编码,导致协议分离失败
解析器绕过漏洞的复杂性,不在单个函数是否调用,而在整个数据流中任意一个环节用了错误的编码方式、漏掉了某个上下文、或者信任了不该信任的标记(比如v-pre)。排查时,必须沿着用户输入从进来到渲染的每一步,问一句:“这一步的输出,会被哪一层解析器怎么看待?”
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











