直接用 innerhtml 渲染用户输入极易引发 xss,应禁用 unsafe-inline、使用 dompurify 等解析器级净化库,并按上下文严格转义;csp 需配合 nonce 动态生成与 report-only 模式渐进实施。

直接用 innerHTML 渲染用户输入,基本等于在登录页贴一张“欢迎黑客”的便签——XSS 漏洞八成从这儿开始;而所谓“前端校验防注入”,纯属自我安慰,SQL 注入的战场从来不在 HTML 里。
怎么快速定位高危的 innerHTML 使用点
浏览器控制台搜 innerHTML =、.innerHTML +=、document.write( 最直接。但更隐蔽的是框架中绕过默认防护的写法,比如 Vue 的 v-html 或 React 的 dangerouslySetInnerHTML。
- 检查所有接收后端返回字段并插入 DOM 的位置,尤其是评论、通知、富文本内容渲染处
- 注意拼接字符串再赋值的场景:
el.innerHTML = '<div>' + data.content + '</div>'—— 即使 data.content 看似“干净”,只要来源不可信,就是风险点 - 别忽略第三方组件回调:某些图表库、编辑器插件会暴露 HTML 插入接口,文档里常写“仅用于可信数据”,但业务代码未必守约
DOMPurify 为什么比手写正则靠谱
正则匹配 <script></script> 根本拦不住 <script></script>、<img onerror="alert(1)">、或带注释的变体 <script><!-- -->alert(1)</script>。DOMPurify 是基于真实 HTML 解析器重建 DOM 树,逐节点校验标签、属性、协议和事件处理器。
- 默认已禁用
script、iframe、所有on*属性、javascript:和data:协议 - 白名单必须显式声明:
DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['p','a','img'], ALLOWED_ATTR: ['href','src','class']}) - 不推荐用
FORBID_TAGS黑名单模式——新 HTML 标签(如base、form)一出就可能被绕过
服务端 HTML 净化不能靠字符串替换
Java 项目里用 String.replace("<script>", "")</script> 或正则删标签,等于给门装了纸糊锁。攻击者早备好大小写混写、自闭合、注释包裹等几十种绕过手法。
- 必须用解析器级净化库:Java 推荐
jsoup的Cleaner类,Python 用bleach,Node.js 用sanitize-html - 白名单策略优先选
Safelist.basicWithImages()起步,而非relaxed()—— 后者放行table、style,易引发 CSS 注入 - 对
href和src必须限制协议:safelist.addProtocols("a", "href", "https", "http"),否则javascript:alert(1)仍能执行
CSP 配置最容易被忽略的三个细节
CSP 不是加个 meta 标签就完事。没配 nonce 却允许内联脚本,等于把防盗门钥匙挂门把手上;只设 report-uri 却不看报告,等于装了监控却从不回看录像。
-
script-src中禁用unsafe-inline后,所有内联<script></script>必须带nonce属性,且该 nonce 值需每次响应动态生成、单次有效 -
default-src 'self'是基线,但若漏掉frame-ancestors 'self',可能被嵌入钓鱼页做点击劫持 - 先用
Content-Security-Policy-Report-Only头上线跑几天,收集真实违规日志,再切到强制模式——硬上容易把正常功能干掉
真正难的不是写对一行 CSP 头,而是厘清每个用户输入字段最终流向哪一层:是进 JS 字符串?HTML 属性?URL 参数?还是模板引擎的表达式?同一段输入,在不同上下文要套不同转义规则,漏掉一个上下文,整条链就断了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











