必须用 bcrypt 哈希密码(带盐、可调成本),禁用明文、base64、SHA256 或 MD5;Session Cookie 需设 Secure/HttpOnly/SameSite;用 gorilla/sessions 并正确配置后端与密钥;通过 context.Context 安全透传用户 ID,避免越权。

用 bcrypt 哈希密码而不是明文存储
用户密码绝不能以明文或简单编码(如 base64)存入数据库。Go 生态中首选 bcrypt,它自带盐值、可调难度,且防彩虹表和暴力破解效果好。
常见错误是直接用 sha256.Sum256 或 md5 —— 这些函数快、无盐、易被 GPU 破解,完全不适用于密码存储。
- 使用
golang.org/x/crypto/bcrypt包,调用bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)生成哈希 - 验证时用
bcrypt.CompareHashAndPassword(hashed, password),不要自己解析哈希字符串 -
bcrypt.DefaultCost默认是 10,生产环境可考虑升到 12–14(注意 CPU 负载上升) - 哈希结果是字符串(如
$2a$10$...),可直接存进string类型字段,无需额外序列化
用 http.SetCookie + Secure/HttpOnly 发送 Session Cookie
如果不用 JWT 做无状态鉴权,而是走传统服务端 session(比如配合 gorilla/sessions),Cookie 的安全属性必须显式设置,否则极易被 XSS 或中间人窃取。
典型疏漏:只调用 http.SetCookie(rw, &http.Cookie{...}) 却忽略关键字段,导致 Cookie 在 HTTP 明文传输、或被前端 JS 读取。
立即学习“go语言免费学习笔记(深入)”;
- 务必设
Secure: true(仅 HTTPS 传输),开发时若用 localhost,可临时加http://localhost:8080并配自签名证书,或用Secure: false但仅限非生产环境 - 务必设
HttpOnly: true,阻止document.cookie访问,大幅降低 XSS 泄露 session ID 风险 - 建议设
SameSite: http.SameSiteStrictMode或http.SameSiteLaxMode,缓解 CSRF - 避免手动拼接
Set-Cookieheader;用标准库http.SetCookie,它会自动处理转义与格式
用 gorilla/sessions 管理内存/Redis 后端 Session
Go 标准库没有内置 session 支持,gorilla/sessions 是最稳定、文档清晰的第三方方案。关键不是“怎么存”,而是“怎么防篡改”和“怎么清理过期”。
容易踩的坑包括:用 cookieStore 却没设加密密钥、用 memstore 上线后重启丢失全部 session、Redis store 忘记配置超时时间导致内存泄漏。
- 初始化
cookieStore时,密钥长度至少 32 字节(如用crypto/rand.Read生成),不可硬编码或复用测试密钥 - 生产环境优先用
redis.Store,配合redis.Options{Addr: "...", Password: "..."},并确保每个 session 设置Options.MaxAge - 调用
session.Save(r, w)后 session 才真正写入;忘记这步会导致登录成功但下个请求仍为未登录 - 不要把敏感字段(如角色、权限列表)全塞进 session value;只存最小必要标识(如
user_id),权限查库获取,避免 session 被篡改后越权
用 net/http.Request.Context() 传递认证上下文
在 handler 链路中透传用户身份信息,别用全局变量、也不要在每个函数加 *User 参数。Go 的 context.Context 是标准且线程安全的方式。
很多人在 middleware 解析完 token 或 session 后,直接把 user.ID 存进 r.Context(),但后续 handler 没检查是否为空,导致 panic 或静默越权。
- 定义 key 类型:
type contextKey string; const userCtxKey contextKey = "user",避免字符串 key 冲突 - middleware 中用
ctx := context.WithValue(r.Context(), userCtxKey, user),再r = r.WithContext(ctx) - 下游 handler 必须用
user, ok := r.Context().Value(userCtxKey).(*User)判断ok,不可假设一定存在 - 不要把密码、token 字符串本身塞进 context;只传结构体指针或 ID,减少内存占用与泄露面
X-Forwarded-Proto,否则 Secure Cookie 可能压根不发。










