动态脚本注入风险源于用户可控数据未经上下文适配进入执行环境,核心对策是切断“输入→执行”直通路径;innerHTML赋值前必须转义,纯文本场景应使用textContent。

动态脚本注入风险(即 XSS)不是代码“写得不够漂亮”导致的,而是数据流失控的结果:用户可控内容未经上下文适配就进入执行环境。核心对策不是禁用功能,而是切断“输入 → 执行”的直通路径。
innerHTML 赋值前必须做转义或替换
直接 el.innerHTML = userInput 是最常见、最高危的漏洞入口。浏览器会解析字符串里的所有标签和事件属性,哪怕只是 <img src="x" onerror="alert(1)" alt="降低动态脚本注入风险的HTML代码质量最佳实践" > 也会触发执行。
- 纯文本场景一律改用
el.textContent = userInput—— 它自动把变成 <code><,无需手动调用转义函数 - 需要保留部分 HTML 格式(如富文本)时,绝不能自己写正则过滤,必须用
DOMPurify.sanitize()这类经审计的库,并严格配置白名单:allowedTags: ['p', 'br', 'strong', 'em'] - Vue 中禁用
v-html,React 中禁用dangerouslySetInnerHTML,除非你已对值做过DOMPurify处理
模板字符串拼接时要分清上下文
用反引号拼 HTML 字符串(如 `<div>${userInput}</div>`)和 innerHTML 一样危险——它只是语法糖,最终仍会交给浏览器解析。
- 若插入位置是 HTML 内容区(如
<div>${...}</div>),必须先转义:he.escape(userInput)(Node.js)或htmlEscape(userInput)(前端工具函数) - 若插入位置是属性值(如
`<a href="https://www.php.cn/link/b85b19cea2f0268e105f30d78f668250">`</a>),需额外校验协议:拒绝javascript:、data:等危险 scheme - 若插入位置是 JavaScript 字符串上下文(如
`const msg = "${userInput}";`),要用 JSON.stringify() 包裹,防止引号逃逸
服务端输出必须启用默认转义
前端再小心,也挡不住服务端模板直接吐出未转义内容。比如 EJS 的 和 Jinja 的 {{ value }} 默认不转义,而 或 {{ value | safe }} 是显式关闭防护的开关。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
立即学习“前端免费学习笔记(深入)”;
- PHP 模板中,始终用
htmlspecialchars($input, ENT_QUOTES, 'UTF-8'),而非echo $input - Java 模板(Thymeleaf)用
th:text="${value}",避免th:utext;Spring Boot 默认已开启 HTML 转义 - Node.js 的 Nunjucks、Handlebars 默认转义,但一旦用了
{% raw %}{{ value }}{% endraw %}就等于开门揖盗
CSP 不是补丁,而是最后一道闸门
Content-Security-Policy 头无法修复漏洞本身,但它能大幅限制攻击载荷的破坏力。比如即使 innerHTML 漏洞存在,CSP 也能阻止 fetch() 外发、禁止内联脚本执行。
- 基础策略至少包含:
default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self' - 绝对不要加
'unsafe-inline'或'unsafe-eval',除非你在用 WebAssembly 或特定构建工具,且已评估过全部风险 - 对必须加载的第三方脚本(如统计 SDK),用 nonce 或 hash 显式授权:
script-src 'nonce-abc123',并在对应<script nonce="abc123"></script>标签中匹配
真正难的不是记住这些规则,而是每次插入用户数据时,下意识问一句:“这段数据最终会落到哪个执行上下文里?”——HTML 内容、属性值、JS 字符串、URL 参数、CSS 表达式,每个上下文都需要不同的转义方式。漏掉任何一个,都可能让整个防护链失效。


















