JWT 令牌详解:结构、安全性与最佳实践
JSON Web Token 出现在几乎所有现代认证系统中。Authorization 头部中那个长字符串——eyJhbGciOiJIUzI1NiIs...——就是一个 JWT,理解它的内部结构和工作原理对于构建安全的应用程序至关重要。
什么是 JWT?
JWT 是一种紧凑的、URL 安全的令牌格式,用于在两方之间传递声明(数据)。它是自包含的——令牌本身携带了验证其真实性和提取用户数据所需的信息,无需查询数据库。
使用我们的 JWT 编码器/解码器 即时解码任何 JWT。粘贴一个令牌,即可查看其 header、payload 和 signature 的详细解析。
JWT 结构:三个部分
每个 JWT 都有三个 Base64URL 编码的部分,由点分隔:
header.payload.signature
Header
{
"alg": "HS256",
"typ": "JWT"
}
指定签名算法和令牌类型。
Payload
{
"sub": "user123",
"name": "Alex Chen",
"role": "admin",
"iat": 1708963200,
"exp": 1709049600
}
包含声明——实际的数据。标准声明包括 sub(主题)、iat(签发时间)和 exp(过期时间)。
Signature
通过使用密钥对编码后的 header 和 payload 进行签名来创建。这可以防止篡改——任何修改都会使签名无效。
JWT 认证的工作流程
- 用户使用凭据登录
- 服务器创建包含用户声明的 JWT 并签名
- 服务器将 JWT 返回给客户端
- 客户端在后续请求的 Authorization 头部中携带 JWT
- 服务器验证签名并提取声明——无需查询数据库
安全最佳实践
始终验证签名
永远不要在未验证签名的情况下信任 JWT。在开发过程中,使用我们的 JWT 解码器 来检查令牌的 payload,但在生产环境中务必进行密码学验证。
使用较短的过期时间
JWT 一旦签发就无法撤销(不同于会话令牌)。保持较短的过期时间(15-60 分钟),并使用刷新令牌来维持长期会话。
选择合适的算法
- HS256 — 使用 SHA-256 的 HMAC,对称密钥。简单、快速,适合单服务器应用
- RS256 — 使用 SHA-256 的 RSA,非对称密钥。更适合多个服务需要验证令牌的分布式系统
- 永远不要使用 "none" —
alg: "none"漏洞已经导致了真实世界的安全事件
保护好密钥
你的 JWT 签名密钥是认证系统的主密钥。安全存储、定期轮换,永远不要在客户端代码中暴露。
不要在 Payload 中存储敏感数据
JWT 的 payload 是 Base64 编码的,不是加密的。任何人都可以解码。永远不要包含密码、信用卡号或机密信息。
常见的 JWT 错误
- 不验证过期时间 — 始终检查
exp声明 - 将 JWT 存储在 localStorage 中 — 容易受到 XSS 攻击。应使用 httpOnly cookie
- 令牌过大 — JWT 会出现在每个请求头中。保持 payload 精简
- 不使用 HTTPS — 通过 HTTP 传输的 JWT 可能被截获
常见问题
JWT 可以被撤销吗?
不能直接撤销——JWT 是无状态的。变通方案包括:较短的过期时间、令牌黑名单,或者更改签名密钥(这会使所有令牌失效)。
我应该用 JWT 来管理会话吗?
JWT 非常适合 API 认证和微服务。对于传统的 Web 会话,使用 cookie 的服务器端会话通常更简单、更安全。
JWT 和 OAuth 有什么区别?
OAuth 是一个授权框架。JWT 是一种令牌格式。OAuth 可以使用 JWT 作为访问令牌,但它们解决的是不同的问题。
相关资源
- Base64 编码详解 — 了解 JWT 使用的编码方式
- JWT 安全性详解 — 深入了解漏洞
- JWT 编码器/解码器 — 即时解码和创建 JWT
- 哈希生成器 — 探索 JWT 签名背后的算法