可信设备识别需用服务端签名Cookie:生成UUID设备ID,以HMAC-SHA256签名后写入HttpOnly、Secure、SameSite=Lax的Cookie;每次请求必须校验签名有效性,签名不匹配则视为无效设备。

Cookie 设备标识不能靠 User-Agent 伪造字段
浏览器的 User-Agent 是客户端可篡改的字符串,直接存进 Cookie 当设备 ID 会失效——用户清 Cookie、换浏览器、开无痕模式,ID 就断了;更严重的是,攻击者能手动 document.cookie = "device_id=xxx" 伪造任意值。真正可用的设备识别必须结合服务端可控逻辑。
用加密签名 Cookie 实现可信设备指纹
核心思路:服务端生成唯一标识(如 UUID),用密钥签名后写入 Cookie,后续请求校验签名有效性,避免客户端篡改。不依赖前端传参,也不暴露原始 ID。
-
c.SetCookie()写入前必须构造*http.Cookie实例,不能直接塞字符串 - 签名推荐用
hmac+sha256,密钥长度 ≥ 32 字节,硬编码在配置里(别用"123") - Cookie 属性要设
HttpOnly=true(防 XSS 读取)、Secure=true(仅 HTTPS 传输)、SameSite=Lax(防 CSRF) - 示例写法:
cookie := &http.Cookie{ Name: "device_sig", Value: signedDeviceID, // hmac.Sum256([]byte(deviceID + secret)).Hex() Path: "/", HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, MaxAge: 3600 * 24 * 30, // 30 天 } c.SetCookie(cookie)
读取时必须验证签名再解析设备 ID
只读 c.Cookie("device_sig") 拿到的是原始字符串,不验证就当设备 ID 用,等于开门揖盗。每次请求都得重新计算签名比对。
- 若
c.Cookie("device_sig")返回http.ErrNoCookie,说明是新设备,需生成新 ID 并签发 - 签名不匹配要当作无效设备处理(比如降级为游客权限,或强制重新绑定)
- 不要把设备 ID 存进
session.Values—— Session 过期策略和 Cookie 不一致会导致状态错乱 - 设备 ID 本身建议用
uuid.NewString()生成,避免从 IP 或 UA 衍生(隐私合规风险)
注意跨子域与移动端 WebView 的兼容边界
如果你的前端分布在 app.example.com 和 api.example.com,Cookie 默认不共享。必须显式设 Domain=".example.com" 才能打通,但要注意:iOS WKWebView 对带点的 Domain 值校验更严,Domain=".example.com" 可能被拒绝写入,而 Domain="example.com" 在部分安卓 WebView 中又不生效。
- 测试时用
c.Request().Host打印实际域名,确认是否含 www 或子域前缀 - 移动端首次加载页面时,WebView 可能尚未完成 Cookie 初始化,
c.Cookie()返回 nil 是正常现象,需兜底逻辑 - 别用
MaxAge=0依赖会话 Cookie —— Android Chrome 自 2023 年起默认关闭“后台进程保留 Cookie”选项,切到其他 App 后可能丢失
设备指纹的可靠性永远卡在“服务端可控”和“客户端不可信”的边界上。签名 Cookie 是目前平衡安全、兼容与实现成本的最简路径,但它的本质仍是弱绑定——真要强设备识别,得走 TLS 客户端证书或 OEM 级硬件 ID,那已超出 HTTP Cookie 能力范围。


















