应优先用textContent渲染纯文本以防止XSS,必须插入HTML时须经DOMPurify等白名单净化;禁止将未经处理的input.value、URL参数、JSON数据直接赋值给innerHTML、v-html或dangerouslySetInnerHTML。

输入框值直接拼进innerHTML会触发XSS
只要用户输入内容未经处理就赋给element.innerHTML,浏览器就会解析执行其中的标签和事件。比如在评论区、搜索高亮、后台富文本预览等场景,input.value或textarea.value被直接塞进innerHTML,就是最典型的漏洞入口。
常见错误写法:
const input = document.querySelector('#comment');
const output = document.querySelector('#display');
output.innerHTML = input.value; // 危险!
测试时输入<img src=x onerror=alert(1)>,页面弹窗即确认漏洞存在。
- 不要用
innerHTML、insertAdjacentHTML()、document.write()接收任意输入 - 若需保留格式,必须先过
DOMPurify.sanitize()白名单过滤,不能只靠正则删<script> -
textContent安全但仅限纯文本——它不渲染任何 HTML,但也不支持<b>这类格式
URL参数反射到页面未转义是反射型XSS高发点
很多搜索页、错误提示页会把location.search里的q或msg参数直接插入 DOM,例如?q=%3Cscript%3Ealert(1)%3C/script%3E解码后渲染,就构成反射型 XSS。
立即学习“前端免费学习笔记(深入)”;
排查方法:
- 手动修改 URL 参数,插入
<script>alert(1)</script>或<img src=x onerror=fetch('/log?c='+document.cookie)> - 检查开发者工具 Elements 面板,看该参数是否原样出现在 HTML 中(未被
等实体编码) - 注意:有些前端框架(如 Vue)对
v-html绑定不做自动转义,{{ q | safe }}这类模板写法也属高危
富文本编辑器输出未净化等于主动放行XSS
富文本不是“例外”,而是风险集中区。用户提交的<p onclick="fetch('/admin/delete')">正文</p>或<img src="x" onerror="alert(1)">,如果后端只做htmlspecialchars()存储、前端再用dangerouslySetInnerHTML渲染,onerror 仍会执行。
关键判断点:
-
strip_tags()不校验属性,htmlspecialchars()不解析结构,二者都不能用于富文本 - 必须使用上下文感知的净化库:
DOMPurify(前端)、bleach(Python)、sanitize-html(Node.js),并显式配置白名单 - 白名单要细粒度控制:比如允许
<a>但限制href协议为http、https、/,禁用javascript:
JSON数据插入<script>标签前未做JS上下文编码</script>
后端返回 JSON 给前端,常被写成<script>window.data = ${JSON.stringify(userInput)};</script>。一旦userInput含"或</script>,就会提前闭合标签,导致后续 JS 执行。
正确做法不是避免 JSON,而是按上下文编码:
- 在 HTML 属性中插 JSON:用
htmlEscape(如 Go 的html/template) - 在
<script>内插 JSON:用jsEscaper(Go)或 JavaScript 的JSON.stringify()+replace()处理</script>和\u2028/\u2029 - 绝对不要把用户输入拼进
eval()、setTimeout()字符串参数或new Function()
最易被忽略的是:JSON 本身安全,但一旦离开 JSON 上下文(比如JSON.parse()后再拼 HTML),就必须立刻按目标上下文重新转义——不能假设“刚解析完的数据还是干净的”。



















