模板字符串本身不防XSS,但配合带标签函数可实现安全HTML插值;关键是对插值内容默认转义,遍历values做HTML实体编码(如

模板字符串本身不防 XSS,但配合带标签函数(tagged template literals)可以实现安全的 HTML 插值 —— 关键在于**对插值内容做默认转义**,而非直接拼接。
带标签函数是防 XSS 的核心机制
标签函数接收模板字符串的静态部分(strings)和动态插值部分(values),你完全控制如何组合它们。默认行为是不做任何处理,但你可以主动对每个 values 做 HTML 实体编码:
- 遍历所有插值值,用
encodeURIComponent或更合适的 HTML 转义函数(如转义→、"→"等) - 将转义后的值与静态字符串逐段拼接,确保用户输入永不被解析为 HTML/JS
- 避免使用
innerHTML直接写入结果;推荐用textContent或createTextNode渲染纯文本,或用insertAdjacentHTML+ 严格校验白名单标签(进阶场景)
一个基础但有效的安全标签函数示例
下面是一个轻量、可复用的 html 标签函数,只对插值内容转义,保留模板中的原始 HTML 结构(静态部分):
function html(strings, ...values) {
const escape = s => String(s)
.replace(/&/g, '&')
.replace(/, '/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
let result = strings[0];
for (let i = 0; i alert("xss")';
const content = html`<div>Hello ${user}!</div>`;
// → <div>Hello <script>alert("xss")</script>!</div>
// 插入到页面时显示为纯文本,不会执行脚本
注意边界情况与增强方向
基础转义能防御大部分反射型/存储型 XSS,但需留意:
-
URL 上下文需单独处理:若插值用于
href或src,仅 HTML 转义不够,应使用encodeURI或encodeURIComponent,并限制协议(如只允许https:、mailto:) -
样式属性(style)需特殊过滤:避免插入
javascript:、expression()或未转义的url()内容;建议禁用内联 style,改用 CSS 类名控制 - 不信任静态字符串:如果模板字符串本身来自用户输入(如后端返回的模板),那整个机制失效 —— 标签函数只保护 插值部分,静态部分必须可信
-
结合 DOM API 更安全:最终渲染时优先用
element.textContent = …或document.createTextNode(),比生成 HTML 字符串再innerHTML更可靠
生产环境推荐方案
不要从零手写安全函数。直接使用成熟库更稳妥:
- DOMPurify:对已生成的 HTML 字符串做白名单过滤(适合富文本)
- lit-html 或 hyperlit:编译期绑定 + 运行时自动转义,天然防 XSS
-
React / Vue / Svelte:框架默认对 JSX / 模板插值做转义,只要不用
dangerouslySetInnerHTML或v-html就很安全
自己实现标签函数适合学习原理或极简场景;真实项目请优先依赖经过审计的方案。










