html/template 默认防 XSS 因其按上下文自动转义,text/template 仅简单 HTML 实体转义且无上下文识别能力;绕过防护包括显式使用 template.HTML、预转义、JS 中未用 js 过滤器等。

为什么 html/template 默认能防 XSS 而 text/template 不能
html/template 在解析时会根据上下文(如标签属性、JS 字符串、CSS 值、HTML 内容等)自动选择对应的转义策略;text/template 只做简单 HTML 实体转义(如 → zuojiankuohaophpcn),不识别上下文,无法防御 onclick="alert(1)" 这类属性内执行的 XSS。
常见错误现象:用 text/template 渲染用户输入到 href 或 onclick 中,结果触发 JS 执行。
使用场景:只要最终输出目标是 HTML 页面,一律用 html/template;仅生成纯文本、JSON、邮件正文等非 HTML 内容时才考虑 text/template。
哪些写法会绕过 html/template 的自动防护
自动防护只在「模板原生插值」中生效。以下操作会跳过转义逻辑:
立即学习“go语言免费学习笔记(深入)”;
- 显式调用
template.HTML包装字符串(如{{ .SafeHTML | safeHTML }})—— 你得自己确保内容可信 - 用
url.QueryEscape或html.EscapeString预处理后再传入模板 —— 多余且可能双重转义 - 在 JS 上下文中直接插入未标记为
template.JS的变量(如var x = "{{ .RawJS }}";)—— 这里必须用{{ .RawJS | js }} - 把用户输入拼进
href时没走url函数(正确写法:...)
性能影响:手动绕过防护本身不慢,但一旦出错,XSS 漏洞比性能问题严重得多。
html/template 中不同上下文对应的安全函数
模板会自动推断上下文,但有时需要显式标注。关键函数有:
-
{{ .Content | html }}:强制作为 HTML 片段渲染(等价于template.HTML) -
{{ .JSCode | js }}:在 JS 字符串或表达式中安全插入(转义成\x3c等) -
{{ .URL | url }}:用于href、src等 URL 属性(校验协议白名单,过滤javascript:) -
{{ .CSS | css }}:用于style属性或标签(防止expression()等 IE 旧特性)
注意:url 函数默认只允许 http、https、mailto、tel 等协议;若需支持 ftp,得自定义函数并严格校验。
动态构建 HTML 标签时的典型陷阱
比如要根据数据生成带 class 的 这完全绕过了模板的上下文感知, 或者用 最容易被忽略的是:模板函数链式调用(如 {{ printf `
.Class 和 .Content 都不会被检查。正确做法是拆解为原生模板结构:template.HTMLAttr 封装属性值(需在 Go 侧预处理):
data.Class = template.HTMLAttr("my-class " + userClass)
{{ .Input | lower | html }})中,html 必须是最后一个环节,否则后续操作可能破坏转义效果。










