双重 Cookie 验证 (Double Submit Cookie) 是什么防御策略?
双重 Cookie 验证 (Double Submit Cookie) 是一种用于防御 跨站请求伪造 (CSRF, Cross-Site Request Forgery) 攻击的常用策略。
它的核心思想是:利用“同源策略”让攻击者无法读取 Cookie 的特性,要求请求中必须包含一个与 Cookie 值相匹配的参数。
以下是关于该策略的详细解析:
1. 为什么要用它?(背景)
在 CSRF 攻击中,攻击者诱导受害者访问恶意网站,恶意网站会向受害者的目标网站(如银行)发送请求。因为浏览器会自动携带目标网站的 Cookie(包含会话 Session ID),服务器会误以为这是用户本人的操作。
传统的防御方法(如 Synchronizer Token Pattern)需要在服务器端(Session 中)存储一个随机 Token 来验证。但在分布式系统、微服务或无状态(Stateless)架构中,服务器端存储 Session 比较麻烦(需要共享 Session 存储)。
Double Submit Cookie 的最大优势在于:服务器不需要存储 Token,它是“无状态”的。
2. 工作原理 (流程)
这个策略要求请求中包含两份相同的 Token:一份在 Cookie 中,一份在请求参数(或 HTTP Header)中。
- 生成 Token:
当用户登录或访问页面时,服务器生成一个随机的、加密强度高的 CSRF Token。 - 设置 Cookie:
服务器将这个 Token 放入用户的 Cookie 中(通常是一个单独的 Cookie,例如叫csrf_token,不同于 Session ID)。 - 发起请求:
当用户在页面上提交表单或发送 AJAX 请求时,前端代码(JavaScript)会从 Cookie 中读取这个 Token,并将它放入:- 请求体 (POST Body) 中,或者
- HTTP Header (如
X-CSRF-Token) 中。
- 服务器验证:
服务器收到请求后,会提取 Cookie 中的 Token 和 请求参数/Header 中的 Token 进行对比。- 如果两者一致:请求合法。
- 如果两者不一致或缺失:拒绝请求。
3. 为什么它能防御 CSRF?(核心逻辑)
这个防御策略依赖于浏览器的 同源策略 (Same-Origin Policy):
- 攻击者能做什么: 攻击者可以在恶意网站上构造一个表单,向你的网站发起 POST 请求。浏览器会自动带上你网站的 Cookie(包含那个
csrf_token)。 - 攻击者做不到什么: 攻击者无法读取你网站的 Cookie 内容。
- 结果: 攻击者虽然能让请求带上 Cookie,但他无法知道 Cookie 里的 Token 值是多少,因此他无法在 POST 参数或 Header 中构造出那个必须匹配的 Token。
- 服务器判定: 服务器看到 Cookie 里的 Token 存在,但请求体里的 Token 缺失或错误,判定为攻击。
4. 优缺点分析
优点
- 无状态 (Stateless): 服务器不需要在数据库或内存中保存 Token,这使得它非常适合负载均衡、多服务器部署和 RESTful API。
- 实现简单: 开发成本相对较低,不需要复杂的 Session 管理机制。
缺点与风险
- 子域名漏洞 (Subdomain Exploit):
- 这是该策略最大的弱点。如果攻击者控制了你的某个子域名(例如
blog.example.com被黑,或者允许用户上传内容到子域名),攻击者可以向主域名(.example.com)写入一个伪造的 Cookie。 - 攻击者可以将 Cookie 设置为他知道的值(例如
123),然后在发起的 CSRF 请求参数中也填入123。服务器对比一致,防御被绕过。
- 这是该策略最大的弱点。如果攻击者控制了你的某个子域名(例如
- HttpOnly 限制:
- 为了让前端 JS 能读取 Token 并放入 Header/参数中,这个 CSRF Cookie 不能设置为
HttpOnly。这意味着如果网站存在 XSS (跨站脚本攻击) 漏洞,攻击者可以轻易读取该 Token 并伪造请求。(注:通常 Session ID 会设为 HttpOnly,而 CSRF Token 不设,以此做隔离)。
- 为了让前端 JS 能读取 Token 并放入 Header/参数中,这个 CSRF Cookie 不能设置为
- 中间人攻击 (MitM):
- 如果网站没有全站强制 HTTPS,攻击者可以在中间拦截并修改 Cookie,从而绕过防御。
5. 总结
双重 Cookie 验证 是一种轻量级、易于扩展的 CSRF 防御方案,特别适用于单页应用 (SPA) 和 无状态 API。
最佳实践建议:
- 必须全站 HTTPS,防止 Cookie 被篡改。
- 结合 Signed Cookie (签名 Cookie): 为了防止子域名攻击,服务器在设置 Cookie 时,可以对 Token 进行加密签名(HMAC)。验证时,服务器先解密/验签 Cookie,确信它是由服务器生成的,然后再对比参数中的 Token。这被称为 Signed Double Submit Cookie,安全性更高。
- 现代浏览器中,通常建议结合
SameSiteCookie 属性 (SameSite=Strict或Lax) 一起使用,作为多层防御。