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