模板注入漏洞识别关键在于验证用户输入是否被模板引擎执行:提交{{7*7}}或${3+4}等表达式,若响应返回49或7而非原样输出,即存在ssti;同时检查是否将可控字符串拼入{{}}/{% %}语法域、是否误用text/template渲染html、是否绕过html/template转义机制。

模板注入漏洞怎么识别?看输出是否执行用户输入的表达式
SSR模板注入不是“渲染慢”或“样式错乱”,而是攻击者提交类似${process.env.SECRET}或{{.CurrentUser.Token}}这样的内容后,服务端直接求值并返回敏感信息。典型现象包括:页面中出现意外的环境变量值、服务器日志里有exec或require调用痕迹、HTTP响应体里混入了非预期的JSON或系统路径。
关键判断点有三个:
- 模板引擎是否允许用户可控字符串进入
{{ }}或{% %}语法作用域(如Go的template.Parse传入拼接字符串) - 是否使用
text/template渲染HTML——它不自动转义,html/template才是安全默认 - 是否手动调用
template.HTML包裹未经净化的用户数据,绕过转义机制
Go的html/template为什么不能防住所有注入?上下文切换时容易漏逃逸
html/template的自动转义只在明确上下文中生效,一旦数据被错误地跨上下文使用,就会失效。比如把本该用于JS字符串的值,直接插进onclick="alert('{{.Msg}}')",模板会按HTML文本转义,但"和'没被JS字符串规则处理,导致闭合失败、执行任意代码。
常见踩坑点:
- 在
<script></script>标签内直接{{.RawJS}}——必须用{{.RawJS | js}}显式指定JS上下文 - 写
href="{{.Url}}"时,.Url含javascript:alert(1)——要加| urlquery或白名单协议校验 - 用
template.Must(template.New("x").Funcs(...))注册自定义函数,但函数返回值未标注template.HTML或未做转义
碎片化缓存如何避免XSS污染?缓存键必须带用户态维度
模板碎片缓存不是“缓存越细越好”,而是每一块都得绑定当前用户的可变上下文。如果cache.Get("header")返回的是无状态的通用HTML,而实际页头里有{{.CurrentUser.Name}},那A用户的昵称就可能被B用户看到——这不是UI错乱,是XSS级的数据泄漏。
安全缓存必须满足:
- 缓存键包含
locale、device、role、ab_group四个最小维度,缺一不可 - 禁止对含
{{.Nonce}}、{{.CSRFToken}}、{{.SessionID}}的片段启用缓存 - CDN层需关闭HTML自动优化(如Google Cloud CDN的
optimize-html),否则会重写id或合并script标签,破坏hydration一致性
富文本渲染怎么不踩DOMPurify的坑?别只清标签,还得校验URL协议
DOMPurify.sanitize()能过滤<script></script>,但默认放行@#@#@#@#@#@#@#@#@#@0这种危险链接。很多团队测试时只验证“弹窗没了”,却漏掉静默打点或凭证窃取。
生产环境必须加两道锁:
- 配置
ALLOWED_URI_REGEXP为^https?:\/\/|^\/,强制href和src只能是http(s)协议或相对路径 - 禁用
data-属性(FORBID_TAGS: ['data-*']),防止攻击者用data-onclick绕过事件处理器过滤 - 对返回结果再做一次
textContent比对,确认sanitized.length ——长度没变说明很可能没真正净化
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











