本文目录导读:

Cookie校验本身并不能直接抵御CSRF攻击,甚至在某些情况下会为CSRF攻击提供便利,CSRF攻击的核心正是利用了浏览器自动携带Cookie(尤其是认证Cookie)的特性。
要理解Cookie校验如何参与抵御CSRF,需要先区分两个概念:
- 普通的Cookie认证:浏览器自动在跨站请求中携带Cookie。这恰好是CSRF能成功的前提,而不是防御手段。
- 专门为防御CSRF设计的Cookie技术(如SameSite Cookie、Double Submit Cookie模式)。这才是“利用Cookie抵御CSRF”的正确含义。
以下是详细解释:
为什么“普通Cookie校验”不能抵御CSRF?
假设银行网站 bank.com 使用Session Cookie认证,用户登录后,浏览器持有这个Cookie。
- 正常操作:用户访问
bank.com/transfer?to=Alice&amount=100,浏览器自动带上Cookie,银行端校验Cookie通过,转账成功。 - CSRF攻击:用户访问了攻击者精心构造的页面
evil.com,该页面里有一个隐藏的表单或图片,自动向bank.com/transfer?to=Hacker&amount=100000发起请求。- 浏览器会自动带上
bank.com的Cookie。 - 银行后端只校验了Cookie(“你是谁?”),但没有校验是“谁发起的这个请求”(“你是在我的网站上主动点的按钮,还是被evil.com欺骗的?”)。
- 校验通过,转账完成。
- 浏览器会自动带上
普通Cookie校验只是在验证“请求是来自已登录的用户”,但无法区分该请求是用户自愿发起的,还是被恶意网站伪造发起的,所以它无法防御CSRF。
真正的武器:基于Cookie的CSRF防御方案
既然问题出在“浏览器会自动带Cookie”,那么防御思路就是设计一套机制,让攻击者无法构造出合法的请求,其中两种主流方案都利用了Cookie的某种特性。
SameSite Cookie(最现代、最推荐的方案)
这是直接在Set-Cookie时添加的属性,告诉浏览器什么时候该带这个Cookie,它能从根本上解决问题。
-
SameSite=Lax(推荐默认):- 防御原理:浏览器会阻止跨站请求携带Cookie,但允许一部分“顶级导航”(如用户点击链接进入)携带。
- 效果:
evil.com通过<form><img>或fetch发起的POST/GET请求,都不会携带Cookie,后端校验时发现没有或无效的Cookie,拒绝请求。 - Cookie设置示例:
Set-Cookie: session_id=abc123; SameSite=Lax
-
SameSite=Strict:- 防御原理:完全禁止跨站请求携带Cookie,包括用户点击链接。
- 效果:安全性最高,但用户体验可能受影响(比如从Gmail链接到银行页面,需要重新登录)。
优点:无需后端修改代码,前端零配置,是防御CSRF的最强方案之一。 缺点:依赖浏览器支持(现代浏览器都已支持)。
Double Submit Cookie(双重提交Cookie模式)
当无法使用SameSite(比如需要兼容非常老的浏览器)时,这是一个经典模式。
-
工作原理:
- 用户登录后,服务器在Cookie中设置一个随机且保密的Token(
csrf_token=abc123)。 - 服务器在返回的表单或页面中,也会把这个Token作为隐藏字段或请求头写入。
- 当用户提交请求时,浏览器会自动携带该Token(在Cookie中),同时用户手动提交的表单中也包含该Token(在请求体/请求头中)。
- 服务器校验:Cookie中的Token 是否等于 请求体/请求头中的Token。
- 用户登录后,服务器在Cookie中设置一个随机且保密的Token(
-
为什么能防御CSRF?
- 攻击者在
evil.com构造请求,他可以轻易触发浏览器发送带Cookie的请求。 - 攻击者无法读取
bank.com的Cookie(受同源策略限制)。 - 攻击者也无法知道 Cookie里存的是什么值。
- 攻击者无法在
evil.com的请求体或者请求头中构造出和Cookie里一模一样的Token,当服务器比较两者,发现不匹配,就会拒绝请求。
- 攻击者在
优点:纯前端+后端实现,无需服务端存储额外的Token状态(重复校验逻辑)。 缺点:需要前后端协作,每次请求都需要手动携带Token。
总结对比
| 方法 | 原理 | 是否依赖Cookie本身 | 防CSRF效果 |
|---|---|---|---|
| 普通Cookie校验 | 只验证“用户已登录” | 是(作为认证凭证) | 无效 (甚至帮倒忙) |
| SameSite Cookie | 声明“跨站时别带Cookie” | 是(通过修改Cookie属性) | 极强(最推荐) |
| Double Submit Cookie | 利用攻击者无法读取Cookie的值 | 是(作为秘密载体) | 强(经典方案) |
最佳实践建议
- 首选 SameSite Cookie:为所有主要会话Cookie设置
SameSite=Lax,这能阻挡绝大多数CSRF攻击,且几乎零成本。 - 搭配 SameSite 使用安全方案:如果必须支持复杂跨站场景(如支付回调),不要依赖Cookie的自动携带,而是使用:
- CSRF Token:服务器生成的随机Token,存入Session,前端需要获取后在请求Header中携带(不是Cookie)。
- Origin/Referer验证:检查请求头中的
Origin或Referer字段,确保请求来自本站。
- 避免不安全模式:不要为了兼容性轻易使用
SameSite=None,如果必须用(比如需要第三方Cookie场景),必须同时启用 CSRF Token 或 Origin验证。
一句话结论:Cookie校验本身是CSRF攻击的目标,而不是解药。真正能抵御CSRF的,是SameSite=Cookie属性 或基于秘密Token的校验机制(其中Double Submit Cookie是利用了Cookie无法被跨站读取的特性)。