Skip to content

CSRF Token 与 JWT Token 的全面对比

更新: 5/24/2026 字数: 0 字 时长: 0 分钟

这是一个非常容易混淆的问题——两者都叫 "Token",但它们解决的问题完全不同、所处的层次也完全不同。简单说:CSRF Token 解决"这个请求是不是用户本人发的",JWT 解决"这个用户是谁"

一、一句话本质区别

Token解决的核心问题通俗类比
CSRF Token防止请求伪造——证明"请求来自本站点的合法页面"入场券:证明你是从正门进来的,不是翻墙进来的
JWT Token用户身份认证——证明"你是这个用户"身份证:证明你就是张三,所有人都认可

关键认知:两者不冲突、不替代、可同时存在。一个系统完全可以同时用 JWT 做身份认证 + CSRF Token 做请求防伪。

二、核心维度全面对比

对比维度CSRF TokenJWT Token
全称Cross-Site Request Forgery TokenJSON Web Token
核心目的防御 CSRF 攻击身份认证 / 信息传递
解决的问题请求来源合法性用户身份合法性
本质一个不可预测的随机字符串一段自包含的、签名过的 JSON 数据
内容通常无意义(如 a3f9c2e1b4...包含用户信息(如 {userId, role, exp}
是否可解码不可解码(就是随机串)可解码(Base64Url,任何人都能看内容)
是否含签名无签名有签名(防篡改)
生成方服务端服务端
存储位置(服务端)通常存 Session无需存储(自包含)
存储位置(客户端)HTML 隐藏字段 / <meta> / CookieLocalStorage / 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(签名)

解码后:

json
// 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 头中(推荐做法)

javascript
fetch('/api/transfer', {
  headers: { 'Authorization': 'Bearer ' + jwt }
});
  • 天然免疫 CSRF:因为浏览器不会自动给请求加 Authorization 头,必须由 JS 主动添加。
  • 恶意站点的 JS 在 evil.com 域内运行,读不到 LocalStorage 里的 JWT(同源策略),自然无法构造请求。
  • 此时确实不需要 CSRF Token
javascript
// 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 CookieCSRF Token + SameSite✓ 需要
SPA + JWT in HeaderJWT(Authorization 头)不需要(无 Cookie 自动携带)✗ 不需要
SPA + JWT in CookieJWT CookieCSRF Token + SameSite✓ 需要
移动 App + JWTJWT(自定义 Header)不需要✗ 不需要
微服务(服务间)JWT(内部签名)不需要(非浏览器场景)✗ 不需要

九、各自的安全注意事项

CSRF Token 注意事项

  • ✅ 使用密码学安全的随机数生成器生成
  • ✅ Token 不能放在 URL 中(Referer 泄露)
  • ✅ Token 不能存 LocalStorage(XSS 风险)
  • ✅ 站点必须无 XSS 漏洞(否则防御全废)
  • ✅ 配合 SameSite=Lax Cookie 加固

JWT 注意事项

  • 使用强密钥(HS256 ≥ 256 位;推荐 RS256 非对称)
  • 设置较短的过期时间exp 字段,配合 Refresh Token)
  • 不要在 Payload 放敏感数据(任何人都能 Base64 解码)
  • 存储位置选择
    • LocalStorage:方便但有 XSS 风险
    • HttpOnly Cookie:防 XSS 但有 CSRF 风险(需 CSRF Token 配合)
    • 内存:最安全但页面刷新即丢失
  • 服务端验签必须严格(防御著名的 alg: none 漏洞)
  • 关键操作需要支持撤销(黑名单 / 短期 Token + Refresh)

十、记忆口诀

维度CSRF TokenJWT
回答什么问题这个请求合法吗?这个是谁?
关注层面请求层身份层
有无含义纯随机串含用户信息
服务端是否存通常要存不用存
典型架构传统 WebAPI / 微服务
能防 CSRF 吗这是它的本职看怎么用,放 Header 能,放 Cookie 不能
能认身份吗不能这是它的本职

十一、一个完整请求的对比示例

http
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 应用

http
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 保驾