Go HTTP服务防注入需在每处使用点做上下文校验:SQL用参数化查询,HTML用html/template自动转义,JSON用结构体tag,文件路径用filepath.Clean+白名单校验。
Go 的 net/http 默认不自动过滤或转义用户输入,所有来自 req.URL.Query()、req.FormValue()、req.Body 的数据都应视为不可信。防护核心不是“拦截恶意字符串”,而是“在每个使用点做上下文敏感的校验与转义”。
database/sql 的参数化查询(db.Query("SELECT * FROM users WHERE id = ?", id)),禁用字符串拼接html/template(自动转义),而非 text/temp
late
json: tag,且不直接将用户输入拼进 fmt.Sprintf 生成的 JSON 字符串中filepath.Clean() + 白名单目录前缀校验,例如 path := filepath.Join("/var/www/static", filepath.Clean(filename))
if !strings.HasPrefix(path, "/var/www/static/") {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}Go 标准库不默认设置安全响应头,需手动注入。这些头对缓解 XSS、点击劫持、MIME 类型混淆等至关重要,但顺序和值错误反而会破坏功能。
X-Content-Type-Options: nosniff 防止浏览器 MIME 类型猜测——必须严格设为 nosniff,多一个空格或大小写错误都会失效X-Frame-Options: DENY 或 SAMEORIGIN 控制是否允许 iframe 嵌入;若用 Content-Security-Policy,则此头可省略Content-Security-Policy 是最有效的 XSS 防御手段,但策略过严会导致资源加载失败;建议从宽松起步,如 "default-src 'self'; script-src 'self' 'unsafe-inline'",再逐步收紧func securityHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("Content-Security-Policy", "default-src 'self'")
next.ServeHTTP(w, r)
})
}文件上传是高危操作,Go 没有内置的“安全上传”封装,req.ParseMultipartForm 仅解析表单,不校验内容。风险集中在文件名、类型、大小、存储路径四方面。
Content-Type 和文件扩展名,用 file.Header.Peek(0) 读取魔数(magic bytes)判断真实类型,例如 PNG 文件开头是 89 50 4E 47
uuid.NewString())+ 固定扩展名(从魔数推断),绝不用原始 filename
ParseMultipartForm(maxMemory) 中设合理上限(如 32 表示 32MB),并检查 file.Size
/etc、/root)Go 的 http.SetCookie 默认创建的是非 HttpOnly、非 Secure、无 SameSite 的 cookie,极易被 XSS 窃取或 CSRF 利用。
HttpOnly: true(阻止 JS 读取)、Secure: true(仅 HTTPS 传输)、SameSite: http.SameSiteStrictMode 或 http.SameSiteLaxMode
Domain 字段必须显式指定(如 .example.com),且不能是顶级域名(如 .com)cookie := &http.Cookie{
Name: "session_id",
Value: sessionID,
Path: "/",
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteStrictMode,
MaxAge: 3600,
}
http.SetCookie(w, cookie)安全不是加个中间件就一劳永逸的事。Go 的简洁性意味着它把控制权完全交给你——每个 req.FormValue、每处 io.WriteString、每次 os.OpenFile,都是需要你主动决策信任边界的现场。