CSRF Token 与 JWT Token 的全面对比
更新: 5/24/2026 字数: 0 字 时长: 0 分钟
这是一个非常容易混淆的问题——两者都叫 "Token",但它们解决的问题完全不同、所处的层次也完全不同。简单说:CSRF Token 解决"这个请求是不是用户本人发的",JWT 解决"这个用户是谁"。
一、一句话本质区别
| Token | 解决的核心问题 | 通俗类比 |
|---|---|---|
| CSRF Token | 防止请求伪造——证明"请求来自本站点的合法页面" | 入场券:证明你是从正门进来的,不是翻墙进来的 |
| JWT Token | 用户身份认证——证明"你是这个用户" | 身份证:证明你就是张三,所有人都认可 |
关键认知:两者不冲突、不替代、可同时存在。一个系统完全可以同时用 JWT 做身份认证 + CSRF Token 做请求防伪。
二、核心维度全面对比
| 对比维度 | CSRF Token | JWT Token |
|---|---|---|
| 全称 | Cross-Site Request Forgery Token | JSON Web Token |
| 核心目的 | 防御 CSRF 攻击 | 身份认证 / 信息传递 |
| 解决的问题 | 请求来源合法性 | 用户身份合法性 |
| 本质 | 一个不可预测的随机字符串 | 一段自包含的、签名过的 JSON 数据 |
| 内容 | 通常无意义(如 a3f9c2e1b4...) | 包含用户信息(如 {userId, role, exp}) |
| 是否可解码 | 不可解码(就是随机串) | 可解码(Base64Url,任何人都能看内容) |
| 是否含签名 | 无签名 | 有签名(防篡改) |
| 生成方 | 服务端 | 服务端 |
| 存储位置(服务端) | 通常存 Session | 无需存储(自包含) |
| 存储位置(客户端) | HTML 隐藏字段 / <meta> / Cookie | LocalStorage / SessionStorage / Cookie |
| 传输方式 | 请求参数 / 自定义请求头 | Authorization: Bearer <token> 头 |
| 生命周期 | 通常与 Session 一致 | 独立的过期时间(exp 字段) |
| 是否携带状态 | 有状态(服务端需存储比对) | 无状态(不需服务端存储) |
| 典型使用场景 | 表单提交、敏感操作请求 | API 调用、SSO、跨服务认证 |
| 架构适用性 | 传统有 Session 的 Web 应用 | 前后端分离、微服务、移动端、SSO |
| 能否单点登出 | 容易(删除 Session 即可) | 难(需引入黑名单机制) |
三、本质对比:两者根本不在一个层面
CSRF Token 解决的是「请求层」的问题
"这个发往
/transfer的 POST 请求,到底是用户在我们网站的转账页面上点的,还是别的网站伪造的?"
它和"用户是谁"无关——即使用户已经登录,CSRF Token 也是必要的,因为它防的不是"假冒用户",而是"假冒请求"。
JWT 解决的是「身份层」的问题
"现在调用
/api/profile的这个人,到底是不是张三?我怎么知道?"
它和"请求从哪来"无关——JWT 只关心"这个 Token 是不是我签发的,对应哪个用户",至于请求来自浏览器、Postman、还是攻击者的脚本,它一概不管。
这就是为什么仅用 JWT 不能防御 CSRF(如果 JWT 放在 Cookie 中自动携带的话)。
四、结构对比
CSRF Token 长什么样?
就是一串纯随机字符串,没有任何结构和含义:
csrf_token = "a3f9c2e1b4d7f8e2c9a5b8d1e4f7c2a9"服务端记住"这个 Token 对应哪个 Session"即可。
JWT 长什么样?
由 三段 Base64Url 编码的内容用 . 拼接而成:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMDAxIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzM1Njg5NjAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
↑ Header(算法) ↑ Payload(用户数据) ↑ Signature(签名)解码后:
// Header
{ "alg": "HS256", "typ": "JWT" }
// Payload (任何人都能 Base64 解码看到!)
{ "userId": "1001", "role": "admin", "exp": 1735689600 }
// Signature (服务端用密钥签名,防止篡改)
HMACSHA256(base64(header) + "." + base64(payload), secret)关键特性:
- 自包含:服务端不需要查数据库,从 Token 就能知道用户信息。
- 可验证:签名保证 Payload 没被篡改。
- 可解码但不可伪造:内容公开可见,但没有密钥无法生成有效签名。
五、攻防视角对比
CSRF Token 防的是什么?
防的是:恶意站点伪造用户的请求。 防御原理:恶意站点因同源策略读不到 Token,无法在伪造请求中带上。 防不住什么:XSS(XSS 能直接读到 Token)、Token 本身被窃取。
JWT 防的是什么?
防的是:身份伪造、Token 被篡改。 防御原理:签名机制确保 Token 不能被伪造或修改。 防不住什么:
- 不能防 CSRF(如果存在 Cookie 中自动携带)。
- 不能防 XSS(XSS 可读取 LocalStorage 中的 JWT)。
- 不能轻易撤销(无状态特性的代价)。
六、为什么 JWT 不能替代 CSRF Token?
这是面试和实战中最常被搞错的一点,必须讲清楚:
情况 1:JWT 放在 Authorization 头中(推荐做法)
fetch('/api/transfer', {
headers: { 'Authorization': 'Bearer ' + jwt }
});- 天然免疫 CSRF:因为浏览器不会自动给请求加
Authorization头,必须由 JS 主动添加。 - 恶意站点的 JS 在
evil.com域内运行,读不到 LocalStorage 里的 JWT(同源策略),自然无法构造请求。 - 此时确实不需要 CSRF Token。
情况 2:JWT 放在 Cookie 中(图省事的常见做法)
// JWT 写入 Cookie,后续请求自动携带
document.cookie = 'jwt=' + token;
// 或服务端 Set-Cookie- CSRF 漏洞回来了:浏览器会自动把 Cookie 中的 JWT 带上,恶意站点伪造请求时也会自动携带,CSRF 攻击成立。
- 此时必须配合 CSRF Token / SameSite Cookie。
核心结论:JWT 是否需要配合 CSRF Token,取决于 JWT 怎么存储和传输,而不是 JWT 本身有什么能力。
七、典型使用场景对比
CSRF Token 适用场景
- 传统服务端渲染应用(Spring MVC、Django、Rails、Laravel)
- 基于 Session/Cookie 的认证体系
- 任何使用 Cookie 自动携带凭证的场景
JWT 适用场景
- 前后端分离架构(React/Vue + REST API)
- 微服务体系(服务间传递身份信息,无需共享 Session)
- 移动端 / App 客户端(无 Cookie 概念,天然适合 Header 传递)
- 单点登录 SSO(多个系统共享一份 Token)
- 第三方授权(OAuth 2.0 的 access_token 常用 JWT 格式)
八、组合使用的实战架构
实际项目中,根据架构选择不同的组合方案:
| 架构类型 | 身份认证 | CSRF 防御 | 是否需要两者并存 |
|---|---|---|---|
| 传统 Web(Session) | Session Cookie | CSRF Token + SameSite | ✓ 需要 |
| SPA + JWT in Header | JWT(Authorization 头) | 不需要(无 Cookie 自动携带) | ✗ 不需要 |
| SPA + JWT in Cookie | JWT Cookie | CSRF Token + SameSite | ✓ 需要 |
| 移动 App + JWT | JWT(自定义 Header) | 不需要 | ✗ 不需要 |
| 微服务(服务间) | JWT(内部签名) | 不需要(非浏览器场景) | ✗ 不需要 |
九、各自的安全注意事项
CSRF Token 注意事项
- ✅ 使用密码学安全的随机数生成器生成
- ✅ Token 不能放在 URL 中(Referer 泄露)
- ✅ Token 不能存 LocalStorage(XSS 风险)
- ✅ 站点必须无 XSS 漏洞(否则防御全废)
- ✅ 配合
SameSite=LaxCookie 加固
JWT 注意事项
- ✅ 使用强密钥(HS256 ≥ 256 位;推荐 RS256 非对称)
- ✅ 设置较短的过期时间(
exp字段,配合 Refresh Token) - ✅ 不要在 Payload 放敏感数据(任何人都能 Base64 解码)
- ✅ 存储位置选择:
- LocalStorage:方便但有 XSS 风险
- HttpOnly Cookie:防 XSS 但有 CSRF 风险(需 CSRF Token 配合)
- 内存:最安全但页面刷新即丢失
- ✅ 服务端验签必须严格(防御著名的
alg: none漏洞) - ✅ 关键操作需要支持撤销(黑名单 / 短期 Token + Refresh)
十、记忆口诀
| 维度 | CSRF Token | JWT |
|---|---|---|
| 回答什么问题 | 这个请求合法吗? | 这个人是谁? |
| 关注层面 | 请求层 | 身份层 |
| 有无含义 | 纯随机串 | 含用户信息 |
| 服务端是否存 | 通常要存 | 不用存 |
| 典型架构 | 传统 Web | API / 微服务 |
| 能防 CSRF 吗 | 这是它的本职 | 看怎么用,放 Header 能,放 Cookie 不能 |
| 能认身份吗 | 不能 | 这是它的本职 |
十一、一个完整请求的对比示例
传统 Web 应用(CSRF Token + Session Cookie)
POST /transfer HTTP/1.1
Host: bank.com
Cookie: JSESSIONID=abc123xyz ← Session ID,服务端查对应用户
Content-Type: application/x-www-form-urlencoded
amount=1000&to=alice&_csrf=a3f9c2e1b4d7f8 ← CSRF Token,证明请求来自合法页面JSESSIONID回答"你是谁"_csrf回答"这请求是不是你真发的"
SPA + JWT 应用
POST /api/transfer HTTP/1.1
Host: api.bank.com
Authorization: Bearer eyJhbGc...xQs5c ← JWT,自包含用户身份
Content-Type: application/json
{"amount": 1000, "to": "alice"}Authorization头同时回答"你是谁"和"请求是不是合法"(因为 evil.com 加不上这个头)- 无需额外的 CSRF Token
十二、一句话总结
CSRF Token 是"请求的入场券"——证明这个请求是从本站正门进来的;JWT 是"用户的身份证"——证明持有者就是这个用户。 前者解决"请求伪造",后者解决"身份认证",分属不同安全层面,互不替代。是否需要同时使用,关键看 JWT 的存储方式——放在 Authorization 头里,JWT 一身兼两职;放在 Cookie 里,就必须再配 CSRF Token 保驾。