如何使用Golang实现Cookie安全管理_Golang Cookie加密与验证方法

不能直接用 http.Cookie 存用户身份,因为其明文传输且无完整性校验,攻击者可篡改 user_id 绕过登录;需用 gorilla/securecookie 签名(防篡改)或加密(防读取),并手动校验 exp、服务端二次鉴权。

Go 标准库的 http.SetCookiehttp.Request.Cookies() 本身不提供加密或签名能力,直接存敏感信息(如用户 ID、权限)到 Cookie 是危险的。必须自行实现签名或加密,否则容易被篡改或窃取。

为什么不能直接用 http.Cookie 存用户身份?

标准 http.Cookie 是明文传输(即使走 HTTPS,服务端也无法验证是否被客户端修改过)。攻击者可伪造 user_id=123 并手动设置 Cookie 绕过登录校验。

  • 没有完整性保护 → 攻击者可任意修改值
  • 没有机密性保护 → 敏感字段(如角色、过期时间)暴露在客户端
  • SecureHttpOnly 只是传输/访问限制,不解决内容可信问题

gorilla/securecookie 实现签名+可选加密

这是最常用、经过实战检验的方案。它默认只做 HMAC 签名(防篡改),开启 Encode/Decode 时可额外 AES 加密(防读取)。

import (
    "github.com/gorilla/securecookie"
)

var s = securecookie.New( securecookie.GenerateRandomKey(32), // auth key securecookie.GenerateRandomKey(32), // encrypt key (only if using encryption) )

// 写入带签名的 Cookie func setAuthCookie(w http.ResponseWriter, userID string) { encoded, err := s.Encode("auth", map[string]interface{}{"id": userID, "exp": time.Now().Add(24 * time.Hour).Unix()}) if err != nil { http.Error(w, "encoding failed", http.StatusInternalServerError) return } http.SetCookie(w, &http.Cookie{ Name: "auth", Value: encoded, Path: "/", HttpOnly: true, Secure: true, // 仅 HTTPS SameSite: http.SameSiteStrictMode, MaxAge: 86400, }) }

  • 必须把两个密钥(auth + encrypt)安全保存,不要硬编码在代码里
  • 如果只签名不加密,第二个密钥可传 nil;但只要含敏感字段(如角色),就应启用加密
  • SameSite 建议设为 StrictLax,缓解 CSRF

手动验证 Cookie 时必须检查 exp 字段并拒绝过期数据

securecookie 不自动校验过期时间,它只保证数据未被篡改。你必须在解码后手动检查 exp 是否小于当前时间。

func getAuthFromRequest(r *http.Request) (string, error) {
    cookie, err := r.Cookie("auth")
    if err != nil {
        return "", errors.New("no auth cookie")
    }
var value map[string]interface{}
if err := s.Decode("auth", cookie.Value, &value); err != nil {
    return "", errors.New("invalid or tampered cookie")
}

if exp, ok := value["exp"].(float64); !ok || int64(exp) < time.Now().Unix() {
    return "", errors.New("cookie expired")
}

if id, ok := value["id"].(string); ok {
    return id, nil
}
return "", errors.New("missing user id")

}

  • 类型断言要小心:securecookie 解码 JSON 后数字默认是 float64
  • 不要信任任何来自 Cookie 的字段(包括 roleemail),只用于查库或生成 session,关键权限必须服务端二次确认
  • 避免在 Cookie 中存密码哈希、token 原文等高危信息

真正难的不是加解密逻辑,而是密钥生命周期管理、过期策略与业务上下文的耦合——比如用户登出时如何让旧 Cookie 失效?这需要配合服务端黑名单或短有效期+刷新机制,单纯靠 Cookie 自身无法解决。