安全实践:输入校验、输出转义、CSRF/点击劫持概念与基本防护
Web 安全三板斧:不信任输入、正确编码输出、为浏览器策略兜底。本章给出 Go/Gin 侧可落地的基础实践;更完整的基线以 OWASP 与各库官方文档为准。
1. 输入校验:binding 标签
Gin 内置基于 go-playground/validator 的绑定校验,结构体标签写规则,ShouldBind* 返回错误即参数不合法:
type CreateUserReq struct {
Email string `json:"email" binding:"required,email"`
Age int `json:"age" binding:"required,min=0,max=150"`
Role string `json:"role" binding:"omitempty,oneof=user admin"`
}
var in CreateUserReq
if err := c.ShouldBindJSON(&in); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
常用标签:required、min/max、len、email、oneof、omitempty。跨字段业务规则(如结束时间晚于开始时间)再到 service 层校验。
2. 输出转义
- HTML 输出交给
html/template,{{ .X }}会被自动转义; - 除非完全可信,别用
template.HTML、template.JS关闭转义; - JSON 输出由
encoding/json负责转义,直接c.JSON即可。
3. 密码存储:bcrypt
密码绝不能明文或裸哈希存储,用 golang.org/x/crypto/bcrypt 加盐哈希:
hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
// 登录校验:
if bcrypt.CompareHashAndPassword(hash, []byte(pwd)) != nil {
return errors.New("密码错误")
}
4. CSRF 与点击劫持
概念先分清(以 OWASP 说明为准):
- CSRF:攻击者借浏览器里已登录的 Cookie,诱导用户向目标站发跨站请求。缓解:关键写操作校验 CSRF Token;Cookie 设
SameSite;纯 API 用 Header 里的 Token 认证(而非 Cookie)基本免疫。 - 点击劫持:攻击者用透明 iframe 覆盖诱饵界面骗点击。缓解:响应头
X-Frame-Options: DENY或 CSP 的frame-ancestors。
r.Use(func(c *gin.Context) {
c.Header("X-Frame-Options", "DENY")
c.Header("X-Content-Type-Options", "nosniff")
c.Header("Referrer-Policy", "no-referrer")
c.Next()
})
5. 其他基础项
- 限制请求体大小:上传/大提交接口用
http.MaxBytesReader或r.MaxMultipartMemory; - 错误信息不外泄内部细节(堆栈、DSN),统一错误体;
- 依赖保持更新,关注各库安全公告;
- HTTPS 传输是前提,配置见部署章节。
注意点
- 校验走「默认拒绝」:白名单式规则优于黑名单过滤。
- 转义发生在输出侧,输入侧做长度/类型限制,各管一段。
- CSRF 对纯 Authorization 头认证基本不适用,别硬套 Cookie 那套方案。
小结
安全不是某一个库,而是每层的默认动作:入口校验、出口转义、密码加盐、浏览器策略。先把这些基础项做全,再谈纵深防御与渗透测试。