go模板自动转义可防xss,但template.html会绕过;应预处理用户输入,设x-content-type-options: nosniff,js上下文须用js.marshal而非字符串拼接。

Go模板中自动转义能防XSS,但template.HTML会绕过它
Go的html/template包默认对所有变量插值做HTML实体转义,比如{{.Name}}中的<script></script>会被转成<script>。这是最基础也最有效的防护层。
但开发者常误用template.HTML类型强制跳过转义——一旦数据来自用户输入(如URL参数、表单提交),就等于主动开后门:
func handler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
// 危险!未过滤就标记为安全HTML
data := struct{ Name template.HTML }{template.HTML(name)}
t.Execute(w, data) // XSS payload 直接执行
}
- 仅在你100%确定内容是静态、可信、且不含任何用户可控片段时,才用
template.HTML - 更安全的做法是用
html.EscapeString()预处理后再传入模板,哪怕多一层也不跳过 - 注意:
text/template不提供自动转义,Web场景下严禁混用
HTTP响应头必须设X-Content-Type-Options: nosniff和X-XSS-Protection
浏览器的MIME嗅探机制可能把文本响应(如JSON或用户上传的.txt)当作HTML执行,绕过模板层防护。加X-Content-Type-Options: nosniff能禁用该行为。
X-XSS-Protection: 1; mode=block虽在现代浏览器中已逐步弃用(Chrome 78+移除),但部分旧IE/Edge仍依赖它作为最后一道防线。
立即学习“go语言免费学习笔记(深入)”;
- 用
http.ServeMux时需手动设置:在HandlerFunc开头加w.Header().Set("X-Content-Type-Options", "nosniff") - 若用
gin或echo等框架,优先启用内置安全中间件(如gin-contrib/sessions不自带,得自己写中间件补) - 别依赖
X-XSS-Protection代替编码逻辑——它只是辅助,不是替代方案
用户输入进JS上下文必须用js.Marshal而非fmt.Sprintf
当需要把Go变量注入到内联<script></script>中(例如初始化前端配置),常见错误是直接拼接字符串:
// ❌ 危险拼接
fmt.Fprintf(w, `<script>var user = "%s";</script>`, r.URL.Query().Get("user"))
这无法防止"、\、等字符破坏JS语法结构。正确做法是用<code>json.Marshal生成合法JSON字符串(它会处理引号转义、Unicode编码、控制字符等):
// ✅ 安全写法
user := r.URL.Query().Get("user")
jsonUser, _ := json.Marshal(user)
fmt.Fprintf(w, `<script>var user = %s;</script>`, string(jsonUser))
-
json.Marshal输出带双引号,所以模板里不用再加引号 - 若值为
nil或结构体,确保字段已用json:tag 标记并导出 - 避免用
js.Global().Get("JSON").Call("parse", ...)在前端解析——服务端已序列化好,直接赋值即可
富文本场景不能只靠html.EscapeString,得用白名单过滤库
博客评论、后台编辑器等内容允许有限HTML(如<b>、<a href>),此时html.EscapeString会把所有标签干掉,失去功能;而放行全部HTML又等于放弃防护。
必须用基于白名单的HTML净化器,比如microcosm-cc/bluemonday:
import "github.com/microcosm-cc/bluemonday" policy := bluemonday.UGCPolicy() // 允许常见格式化标签,禁止script/style等 clean := policy.Sanitize(inputFromUser)
-
UGCPolicy默认禁用onerror、javascript:、data:等危险协议和事件属性 - 不要自己正则匹配
<script>——HTML嵌套、注释、大小写、空格变体太多,正则不可靠 - 如果业务要求支持
iframe,务必限制src只允许特定域名,并用sandbox属性加固
最麻烦的从来不是“怎么加防护”,而是“哪条路径漏掉了没过滤”——用户头像URL、API返回的错误消息、日志打印到页面的调试信息,都可能是XSS入口。每次写Write或Execute前,先问一句:这个字符串里有没有一个字节来自外部?










