介绍
身份验证是每个 Web 应用程序的支柱。出现了两种主要模式:无状态 JWT(JSON Web 令牌) 身份验证和 基于状态会话 身份验证。两者都解决相同的问题——在后续请求中验证用户是谁——但它们在存储、撤销和安全属性方面有根本的不同。本文提供了详细的比较,以帮助您选择适合您的应用程序的方法。
智威汤逊结构
JWT 是一个独立的令牌,由三个以点分隔的 base64url 编码段组成:
header.payload.signature
// Header
{
"alg": "HS256",
"typ": "JWT"
}
// Payload
{
"sub": "user123",
"iat": 1712345678,
"exp": 1712349278,
"role": "admin"
}
// Signature (HMAC-SHA256 of header + payload)
| 细分 | 内容 |
|---|---|
| 标题 | 算法(HS256、RS256)和令牌类型 |
| 有效负载 | 声明 — sub(主题)、iat(发布于)、exp(过期)、自定义数据 |
| 签名 | 验证令牌未被篡改 |
由于有效负载仅采用 Base64 编码(未加密),因此敏感数据绝不能放置在有效负载中,除非使用 JWE(JSON Web 加密)。
基于会话的身份验证
在基于会话的身份验证中,服务器存储会话数据(通常在内存、Redis 或数据库中)。客户端仅在 cookie 中保存会话 ID(随机的不透明字符串):
头对头比较
| 方面 | 智威汤逊 | 会议 |
|---|---|---|
| 存储位置 | 客户端持有所有数据 | 服务器保存会话数据 |
| 服务器状态 | 无状态 — 无需数据库查找 | 有状态 — 需要会话存储查询 |
| 可扩展性 | 非常好 - 没有共享会话存储 | 多实例需要集中式Redis/DB |
| 撤销 | 困难 — 有效期至 exp | 立即 — 从存储中删除会话 |
| 代币大小 | 更大(数百字节) | 小(会话 ID ~32 字节) |
| XSS 漏洞 | JS (localStorage) 可访问的令牌 | JS 无法访问 httpOnly cookie |
| CSRF 保护 | 需要人工处理 | SameSite cookie + CSRF 令牌 |
JWT 的撤销挑战
JWT 最显着的弱点是撤销。一旦发出,JWT 将保持有效,直到其 exp 声明为止。如果用户注销、更改密码或被禁止,则在没有服务器端状态的情况下令牌无法失效,这违背了无状态前提。
缓解策略
1.短期访问令牌+刷新令牌:
// Access token: 15 minutes
// Refresh token: 7 days (stored in database)
访问令牌的 TTL 很短,因此如果泄露,损害是有限的。刷新令牌存储在服务器端,因此可以撤销。
2.令牌黑名单(拒绝名单):
// On logout, add jti (JWT ID) to Redis with TTL matching token expiry
await redis.set(`blacklist:${jti}`, 'true', 'EX', remainingTTL);
这会重新引入服务器状态,但仅针对已撤销的令牌,而不是所有活动会话。
3.轮换令牌签名密钥:
更改签名密钥会使所有令牌失效——这是一种生硬但有效的紧急工具。
XSS 和 XSRF 注意事项
| 威胁 | JWT(本地存储) | 会话(httpOnly cookie) |
|---|---|---|
| XSS | 令牌通过 document.cookie 或 localStorage 被盗 | JS 无法访问令牌(仅 http) |
| CSRF | 不容易受到攻击(手动授权标头) | 没有 SameSite 或 CSRF 令牌就容易受到攻击 |
存储在 localStorage 中的 JWT 容易受到 XSS - 任何注入的脚本都可以读取它们。 HttpOnly cookie 可以防止这种情况,但需要 CSRF 保护,因为 cookie 是自动发送的。
JWT 的最佳实践: 将访问令牌存储在 httpOnly、Secure、SameSite=Strict cookie(不是 localStorage)中。服务器从 Authorization 标头(而不是 cookie)读取它,以避免 CSRF。
// Set JWT in httpOnly cookie
res.cookie('token', jwt, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 15 * 60 * 1000
});
混合方法
许多生产系统结合了这两种模式:
| 方法 | 访问令牌 | 刷新令牌 |
|---|---|---|
| 仅限智威汤逊 | 内存中的 JWT | 带有长 exp 的 JWT |
| 会话式 | 不透明会话 ID | — |
| 混合 | 短暂的 JWT(15 分钟) | 数据库中不透明的刷新令牌 |
混合模型为您提供 JWT 对于大多数请求的无状态效率,同时通过刷新令牌保留撤销功能。
决策矩阵
| 您的首要任务 | 推荐方法 |
|---|---|
| 最小的服务器数据库负载 | JWT(无状态) |
| 即时用户注销/禁止 | 基于会话的 |
| 微服务/API网关 | JWT(传递) |
| 移动应用程序 | JWT(无 cookie 存储) |
| 服务器渲染的 Web 应用程序 | 会话(httpOnly cookie) |
| 第三方API接入 | JWT(不记名令牌) |
结论
没有普遍的赢家。 JWT 在分布式系统、移动应用程序和 API 优先架构方面表现出色,在这些架构中,无状态性非常有价值。会话身份验证为撤销、注销和服务器端安全实施提供高级控制。混合模式——由可撤销刷新令牌支持的短期 JWT——提供了一种务实的折衷方案,既发挥了两种方法的优点,又减轻了它们的缺点。

