不安全。go模板中用自定义函数脱敏存在上下文不可控、无法校验输入、易绕过转义导致xss等问题;应由后端handler层预处理脱敏后再传入模板,确保敏感数据不出现在模板上下文中。

模板里直接用 Go 函数做脱敏安全吗?
不安全。Gin 默认的 html/template 会自动转义,但脱敏逻辑(比如把 13812345678 变成 138****5678)如果写在模板里,只能靠自定义函数——而 Go 模板函数无法访问上下文状态、不能复用业务规则、更没法校验输入合法性。一旦模板里混入用户输入又没严格过滤,容易绕过转义造成 XSS。
推荐做法:后端预处理字段再传给模板
把脱敏逻辑收口到 handler 层,确保原始敏感数据不出现在模板上下文中。这样既可控,也方便统一加审计日志或权限判断。
示例:
// handler 中 user := db.GetUser(id) user.Phone = maskPhone(user.Phone) // 如:13812345678 → 138****5678 user.IDCard = maskIDCard(user.IDCard) // 如:110101199003072358 → 110101**********58 c.HTML(http.StatusOK, "user.html", user)
maskPhone 和 maskIDCard 应该是纯函数,输入字符串,输出脱敏后字符串。注意:
- 空值或格式异常时返回原值 or 空字符串,避免 panic
- 身份证号需校验长度和末位(可用
github.com/gogf/gf/v2/util/gvalid或手写正则),否则可能把脏数据也“脱敏”了 - 手机号建议用
^1[3-9]\d{9}$初筛,别只截前3后4
Gin 注册模板函数风险高,慎用
虽然可以调用 funcMap 注册 maskPhone 到模板,但模板函数在渲染期执行,无超时控制、无错误传播机制,且多个模板共用同一函数实例,状态难追踪。
如果真要用(比如管理后台临时调试),必须:
- 函数内部做完整防御:判空、长度检查、正则匹配,失败直接返回
"***" - 禁止在模板函数里调用 DB、HTTP 或任何可能阻塞的操作
- 注册时函数名带
safe_前缀(如safe_mask_phone),提醒团队这是特殊通道
注册示例:
router.SetHTMLTemplate(template.Must(template.New("").Funcs(template.FuncMap{
"safe_mask_phone": func(s string) string {
if len(s) != 11 { return "***" }
return s[:3] + "****" + s[7:]
},
})))
前端 JS 脱敏是补救,不是方案
有人想用 JS 在页面 onload 后遍历 DOM 替换手机号,这完全不可靠:源码里仍含明文、DevTools 可见、爬虫可直取 HTML。仅适用于「已渲染完成但需临时高亮遮罩」这类极弱场景(如客服系统点击才展开)。生产环境严禁依赖前端脱敏。
真正关键的是:脱敏必须发生在数据离开服务端之前,且要覆盖所有出口——API 返回、日志打印、模板渲染、导出 Excel。漏掉任意一环,就等于没脱敏。











