JWT
本文约需 2 分钟阅读
JWT (JSON Web Token) 是指将 JSON 格式的数据附加电子签名后编码为紧凑字符串的令牌。它于 2015 年作为 RFC 7519 标准化,被广泛用作 OAuth 2.0 的访问令牌以及单点登录 (SSO) 的断言。其最大特点是能够实现服务器端不保留会话信息的无状态认证,随着微服务架构的普及而被迅速采用。
三段式结构 - Header.Payload.Signature
JWT 由用点 (.) 分隔的三个部分构成。每个部分都经过 Base64URL 编码,人类无法直接阅读,但解码后即可以 JSON 形式确认其内容。
JWS 与 JWE 的区别
JWT 这一术语在日常中被用作“签名令牌”的意思,但在规范上存在 JWS (JSON Web Signature) 与 JWE (JSON Web Encryption) 两种类型。
Payload 仅经过 Base64URL 编码,解码后任何人都能读取其内容。签名能够检测篡改,但无法对内容保密。通常被称为“JWT”的大多是这种 JWS 格式。
对 Payload 本身进行加密,只有持有解密密钥的人才能读取内容。其采用五段式结构 (Header、Encrypted Key、IV、Ciphertext、Authentication Tag)。在必须将机密信息包含在令牌中时使用。
在实务中 JWS 的使用占绝大多数。前提是 Payload 中不包含个人信息或机密数据,若必须包含,则应考虑使用 JWE,或者重新审视设计使其根本不包含在令牌中。
无状态认证的优点与风险
采用 JWT 的无状态认证中,服务器不保留会话信息。由于仅验证令牌签名即可完成认证,无需在 Redis 或数据库中管理会话令牌,因此横向扩展十分容易。
| 观点 | JWT (无状态) | Cookie 会话 (有状态) |
|---|---|---|
| 服务器端状态 | 无 (信息包含在令牌本身) | 有 (需要会话存储) |
| 可扩展性 | 高 (任何服务器都可验证) | 需要会话共享机制 |
| 即时失效 | 困难 (需要黑名单机制) | 容易 (只需删除会话) |
| 令牌大小 | 较大 (数百字节至数 KB) | 较小 (仅会话 ID) |
| CSRF 抵抗力 | 使用 Authorization 头时具有抵抗力 | 需要 SameSite 属性等对策 |
最大的风险在于“已签发的 JWT 无法即时失效”这一点。即使用户更改了密码,泄露的 JWT 仍可一直使用到过期为止。为缓解该问题,常见的做法是将访问令牌的过期时间设置得较短 (约 15 分钟),并通过刷新令牌重新签发。在必须即时失效的需求中,应在服务器端维护黑名单,或选择基于 Cookie 的会话管理。
针对 JWT 的代表性攻击
将 Header 的 alg 字段改写为 "none",从而绕过签名验证的攻击。早期的库中有许多接受 alg:none 的实现。作为对策,应在服务器端以白名单方式明确指定允许的算法。
将以 RS256 (非对称密钥) 签名的令牌的 alg 改写为 HS256 (对称密钥),并将公钥用作 HMAC 密钥的攻击。由于公钥任何人都能获取,攻击者便能生成有效的签名。
若 HS256 的密钥是短字符串或可猜测的值,便会被暴力破解确定密钥。必须使用至少 256 比特以上的随机密钥,并定期进行轮换。
会话劫持的手法同样适用于 JWT。将其与加密的基础知识一并理解十分重要。也请一并参阅会话劫持对策、会话令牌窃取的防御措施以及 API 密钥管理的最佳实践。Web 认证相关书籍 (Amazon)推荐用来进行系统性学习。
这篇文章对您有帮助吗?