html/template 默认防 XSS,但需严格使用且不绕过:必须用 html/template 而非 text/template;禁用 safeHTML;过滤前置至 handler 层;属性/JS/CSS 插入须用引号及 template.URL/JSS/CSS;html.EscapeString 不足以防御 XSS。

html/template 默认就能防住绝大多数 XSS,前提是别在关键环节主动绕过它——比如误用 text/template、手动拼 HTML、或把没过滤的用户输入包成 template.HTML。
必须用 html/template,不能用 text/template
这是最常踩的坑。两个包名字只差一个词,行为天壤之别:
-
html/template会根据插入位置(HTML 内容区、href属性、<script></script>内部等)自动做上下文敏感转义 -
text/template完全不转义,拼进去什么就原样输出,{{.UserInput}}里的<script>alert(1)</script>会被浏览器执行 - 错误写法:
import "text/template"+template.New("").Parse(...) - 正确写法:
import "html/template",且确保所有模板解析都走这个包
别在模板里写 {{.Raw | safeHTML}}
这个函数在 Go 1.12+ 已弃用,且容易误导人以为“加个 filter 就安全了”。实际风险极大:
-
safeHTML不做任何过滤,只是把字符串转成template.HTML类型,等于告诉模板“这段我信了” - 如果上游没经过
bluemonday这类白名单过滤器,<img src="https://img.php.cn/" alt="如何在 Go 中使用 html/template 防止 XSS 攻击">就直接上屏 - 过滤逻辑必须提至 handler 层:先
p.Sanitize(userInput),再data.SafeHTML = template.HTML(clean),模板里只写{{.SafeHTML}} - 绝不能对前端富文本编辑器提交的内容跳过这步
属性值、JS、CSS 插入必须用引号 + 类型包装
html/template 的上下文感知依赖你写的结构是否合法。漏掉引号或类型,它就无法准确判断上下文:
- 写成
<a href="https://www.php.cn/link/8627a5992a7f67f8c1e3db85cf9c23eb">link</a>→ 没引号,.URL是javascript:alert(1)时仍可能触发 - 正确写法:
<a href="https://www.php.cn/link/8627a5992a7f67f8c1e3db85cf9c23eb">link</a>,且.URL应是url.URL类型或已用template.URL包装 - 塞进
<script></script>?禁止var url = "https://www.php.cn/link/8627a5992a7f67f8c1e3db85cf9c23eb";这种拼接。改用data-url="{{.URL | json}}+ 前端 JS 读取,或后端用template.JS包装并确保 JSON 序列化 - 样式属性同理:
style="color: {{.Color}}" →必须用template.CSS,否则red; background: url(javascript:...)可能逃逸
别信 html.EscapeString 能防 XSS
它只转义 <、>、"、'、& 这 5 个字符,对真实攻击几乎无效:
立即学习“前端免费学习笔记(深入)”;
- 放进
href或src?javascript:alert(1)、data:text/html,...完全不受影响 - 放进事件属性?
onerror=alert(1)、onmousemove=eval(atob('...'))照样执行 - 仅适用于纯文本插入 HTML 内容区场景,例如
<p>{{.Text}}</p> - 需要校验协议时,必须自己检查:
strings.HasPrefix(url, "https://") || strings.HasPrefix(url, "/")
html/template 失去判断依据,转义就失效了。


















