模板字符串本身不防HTML注入,${}插值仅为纯字符串替换,无转义或校验;直接拼接HTML并用innerHTML插入将导致XSS,必须按输出上下文做对应转义或使用安全标签函数。

模板字符串本身不防 HTML 注入,它只是更方便的字符串拼接工具。${} 插值是纯字符串替换,不做任何转义或上下文校验。直接用它拼 HTML 并插入 DOM,就等于把用户输入原样放进页面——这正是 XSS 的温床。
关键不是“怎么用模板字符串防注入”,而是在使用模板字符串生成 HTML 时,必须配合上下文感知的安全处理机制。
? 模板字符串 + innerHTML = 危险组合
常见错误写法:
const userInput = '<script>alert("xss")</script>';
const html = `<div>${userInput}</div>`;
el.innerHTML = html; // ✅ 执行了脚本!这里模板字符串没做任何防护,userInput 被原样嵌入,浏览器解析时执行脚本。
立即学习“Java免费学习笔记(深入)”;
? 正确做法:按输出上下文做对应转义
| 输出位置 | 推荐方式 | 示例说明 |
|---|---|---|
插入 HTML 文本内容(如 <div>xxx</div>) |
使用 textContent 或手动 HTML 转义函数 |
el.textContent = userInput 安全;若必须拼 HTML,先转义 , <code>>, &, ", '
|
插入 HTML 属性值(如 title="${val}") |
属性值需双重转义(HTML + 引号) | 用 DOMPurify.sanitize() 或专用 escape 函数处理后再插值 |
插入 <script></script> 内联代码或 JSON 数据 |
必须用 JSON.stringify() + template.JS(服务端)或 JSON.parse()(客户端) |
不要用 ${userInput} 直接拼 JS 字符串 |
例如安全拼接属性:
function escapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
const name = '<img src=x onerror=alert(1) alt="JavaScript 中 ES6 模板字符串怎么防范 HTML 注入攻击" >';
const safeHtml = `<span title="${escapeHtml(name)}">Hover me</span>`;? 更可靠的方案:用标签函数封装转义逻辑
定义一个自动转义的标签函数:
function html(strings, ...values) {
let result = '';
strings.forEach((str, i) => {
result += str;
if (i < values.length) {
const val = values[i] == null ? '' : String(values[i]);
result += escapeHtml(val);
}
});
return result;
}
// 使用
const user = '<b>admin</b>';
const output = html`<p>Welcome, ${user}!</p>`;
// → <p>Welcome, <b>admin</b>!</p>这样既保留模板字符串的可读性,又把转义逻辑集中管控。
? 绝对禁止的“伪安全”操作
- ❌
const html =${userInput}+ el.innerHTML = html - ❌
const script =<script>${maliciousCode}</script>+ document.write() - ❌ 把用户数据塞进
${}后再用DOMPurify.sanitize()—— 顺序反了,应先净化再插值 - ❌ 用
template.HTML(Go)或dangerouslySetInnerHTML(React)绕过校验却不做前置过滤
? 补充提醒:服务端渲染场景
Node.js 中用模板字符串拼 HTML 时,同样不能依赖 ${} 自动防护。需搭配:
-
express+ejs/pug等模板引擎的自动转义(默认开启) - 或显式使用
he.escape()、marked()(带 sanitize)、DOMPurify等库预处理
比如:
res.send(`<h2>${he.escape(title)}</h2>`);不复杂但容易忽略。



















