html解析器本身不拦截xss,真正起作用的是dompurify等库的节点遍历净化、csp策略的运行时拦截,以及textcontent替代innerhtml等防御措施。

HTML解析器本身不拦截XSS
浏览器原生的HTML解析器(如Chrome的Blink、Firefox的Gecko)根本不会识别“恶意脚本”并主动拦截。它只按规范解析标签、属性、文本节点,script 标签、onerror 属性、javascript: 协议等,只要语法合法,就会照常加载或执行。
所谓“自动拦截”,其实是后续环节在起作用:DOM构建后触发的CSP策略、渲染前的上下文编码、或第三方库在字符串插入前做的净化。把拦截归因于“HTML解析过程”,是常见误解。
真正起拦截作用的是 DOMPurify 或 sanitize-html 这类库
它们不是在解析时拦截,而是在你调用 DOMPurify.sanitize() 时,先用浏览器原生 parser 构建临时 DOM,再遍历所有节点,按白名单策略移除危险标签和属性。例如:
const clean = DOMPurify.sanitize('@@##@@<script>fetch("/steal?c="+document.cookie)</script>');
结果会是空字符串或仅保留安全的 <img src="x" onerror="alert(1)">(取决于配置),因为 onerror 和 script 默认被剔除。
-
ALLOWED_TAGS控制哪些标签保留(默认几乎全禁) -
ALLOWED_ATTR显式放行属性,比如['src', 'alt', 'class'],但不会放行onerror - 对
javascript:、data:协议的 URL 自动过滤,不靠正则,而是检查实际协议值
服务端 HTML 过滤 ≠ 客户端 DOM 操作安全
很多人以为“后端用了 html-sanitize 库,前端就安全了”,其实不然。如果后端返回的是已净化的 HTML 字符串,但前端又用 innerHTML 插入到某个容器里,而该容器后续又被 JS 动态修改(比如拼接用户输入),那依然可能触发 DOM 型 XSS。
典型错误链:
后端返回安全 HTML → 前端存进 data.content → 用户点击后执行 el.innerHTML = '<div>' + data.content + '</div>' → 看似安全,但如果 data.content 含有 <svg onload="..."></svg> 且未再次净化,就失败了。
- 净化必须发生在“插入 DOM 前一刻”,不能只做一次入库或出库
- 富文本场景建议统一用
DOMPurify.sanitize()包裹所有动态插入操作 - 纯文本内容优先用
textContent而非innerHTML,彻底规避解析风险
CSP 是唯一能在解析后仍生效的“硬拦截”机制
Content Security Policy 通过 HTTP 响应头 Content-Security-Policy 告诉浏览器:“不准执行内联脚本、不准加载非白名单域名的 script”。它在 HTML 解析完成、DOM 构建之后、脚本执行之前介入,属于真正的运行时拦截。
例如设置:Content-Security-Policy: script-src 'self' https://cdn.example.com;
那么即使页面中存在 <script>alert(1)</script> 或 <img>,浏览器也会直接拒绝执行。
- CSP 不依赖 JS 库,也不受 DOM 操作影响,是防线中最刚性的一环
- 但无法防御
eval()、setTimeout(string)、内联事件(除非加'unsafe-inline',这等于自废武功) - 配合
report-uri可捕获绕过尝试,是监控 XSS 实际攻击行为的关键手段
innerHTML = userInput。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











