html本身不执行代码,但它是xss等漏洞的“落地层”,排查重点是用户输入如何进入html、以何方式被解析及是否被当作代码执行;elements面板中灰色斜体节点即为浏览器修复非法html后留下的危险信号。

Elements面板里看到灰色斜体节点就是危险信号
打开 Chrome DevTools 的 Elements 面板,找那些字体灰、斜体、缩进异常的节点。这不是“显示效果问题”,而是浏览器被迫修复非法 HTML 后留下的痕迹。
- 你写了
<div><p>文字</p></div>,实际 DOM 会变成<div><p>文字</p></div>,但中间那段被“吞掉”的结构已破坏语义链 - 灰色斜体节点常伴随
lang属性缺失、<main></main>被包进<div>、或 <code><section></section>出现在<p></p>内部——这些都会让屏幕阅读器失效,也容易成为 DOM XSS 的温床 - 这种结构异常本身不报错,但会让
innerHTML、document.write()等操作的上下文失控,后续 JS 处理时极易误判节点边界 - 典型危险写法:
img.src = '?avatar=' + userInput,攻击者传入javascript:alert(1)或data:text/html,<script>alert(1)</script> - 必须过滤协议:只允许
http:、https:、//(协议相对),严禁javascript:、data:、vbscript: - 域名白名单比正则更可靠:比如只允许
cdn.example.com和images.example.com,而不是用/^https?:\/\/(?!evil)/这类易绕过的规则 - 注意:服务端重写 URL(如代理转发)后,前端仍需二次校验,因为中间层可能被 bypass
- 常见错误场景:评论区富文本回显、搜索关键词高亮(
<mark>xxx</mark>)、后台 CMS 的页面编辑预览 - 简单 replace(/, '3 也转义,且无法处理
onerror、onclick等事件属性 - 正确做法:优先用
textContent;若必须插 HTML,必须调用DOMPurify.sanitize(),且不能只引入不调用 - DOMPurify 默认不放行
javascript:、onerror、style中的expression(),但需确认配置项ALLOWED_TAGS和ALLOWED_ATTR没被放宽 - 高频风险点:
location.search解析参数后直接塞进innerHTML;location.hash用于单页路由,但若未过滤就渲染为标题或内容,就成了 payload 注入口 - 调试方法:在 Sources 面板全局搜索
location.search、location.hash、URLSearchParams,再顺藤摸瓜找 sink(如innerHTML、eval、setTimeout) - 防御关键:所有从 URL 获取的数据,在插入 DOM 前必须走一遍净化流程;不要相信“这个参数只是用来做统计”,攻击者能控制整个 URL
- 额外提醒:
document.referrer和postMessage接收的数据,同样属于不可信源,处理逻辑应一致
src/href属性值来自用户输入时必须校验协议和域名
图片、链接、iframe 的 src 或 href 如果拼接了 URL 参数、localStorage 数据、或表单字段,就极可能被注入恶意载荷。
innerHTML = userContent 是最高危操作,没有之一
只要把未净化的用户数据赋给 innerHTML、outerHTML、document.write(),就等于把解析权完全交给浏览器——它不会区分“这是文本还是入口”。
location.search / location.hash 是 DOM XSS 的主要源头
DOM 型 XSS 不经过服务器,完全在浏览器端触发。攻击者只需构造一个 URL,就能让受害者在无感知下执行脚本。
<img src="x"> 这种明显错误,而是那些在合法标签内、用合法属性名、却偷偷携带恶意行为的组合——比如一个 href 值看似是相对路径,实则被服务端重写为 javascript:;或者一个 data-src 在 JS 中被错误地赋给了 src。这类问题必须结合网络请求、实时 DOM、源码三者交叉验证,缺一不可。











