什么是 JWT?
JWT(JSON Web Token)是一种紧凑的、自包含的令牌格式,用于在各方之间安全地传递信息。它广泛用于:
- 身份认证:用户登录后服务器签发 JWT,客户端携带 JWT 访问受保护资源
- API 授权:微服务之间传递用户身份和权限信息
- 单点登录(SSO):跨域共享认证状态
JWT 的三段结构
JWT 由三个 Base64Url 编码的部分组成,用点(.)分隔:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header.Payload.Signature
^^^^^^ ^^^^^^^ ^^^^^^^^^
声明令牌类型和签名算法:
{
"alg": "HS256", // 签名算法:HS256、RS256、ES256 等
"typ": "JWT"
}
2. Payload(载荷)
包含声明(Claims)——关于用户或实体的陈述:
{
"sub": "1234567890", // subject:用户唯一标识
"name": "John Doe",
"iat": 1516239022, // issued at:签发时间(Unix 时间戳)
"exp": 1516242622, // expiration:过期时间
"iss": "auth.example.com", // issuer:签发者
"aud": "api.example.com" // audience:接收方
}
3. Signature(签名)
用于验证令牌未被篡改:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
如何在线调试 JWT
使用 tool.tl JWT 调试器:
- 打开 tool.tl/jwt-debugger
- 将 JWT Token 粘贴到输入框
- 立即查看解码后的 Header 和 Payload 内容
- 输入 secret 可验证签名是否有效
安全提醒:JWT 的 Payload 只是 Base64Url 编码,不是加密。任何人拿到 JWT 都可以解码查看其中的内容。不要在 Payload 中放置敏感信息(如密码、信用卡号)。
常见 JWT 声明字段
| 字段 | 全称 | 含义 |
sub | Subject | 用户或实体的唯一标识 |
iss | Issuer | 签发者(如 auth.example.com) |
aud | Audience | 接收方(如 api.example.com) |
exp | Expiration | 过期时间(Unix 时间戳) |
iat | Issued At | 签发时间 |
nbf | Not Before | 生效时间(之前不可用) |
jti | JWT ID | 唯一标识符(防重放) |
JWT 常见安全漏洞
1. alg=none 攻击
将 Header 中的 alg 改为 none,绕过签名验证。防御:服务端必须强制指定允许的算法,拒绝 none。
2. 弱 secret
HS256 使用共享密钥,如果 secret 过于简单(如 secret、123456),可被暴力破解。防御:使用至少 256 位的随机 secret。
3. 不验证 exp
服务端不检查 exp 字段,导致过期 Token 仍然有效。防御:每次验证 JWT 必须检查 exp。
各语言生成和验证 JWT
# Python (PyJWT)
import jwt
# 生成
token = jwt.encode({'sub': '123', 'exp': 1700000000}, 'secret', algorithm='HS256')
# 验证解码
data = jwt.decode(token, 'secret', algorithms=['HS256'])
// Node.js (jsonwebtoken)
const jwt = require('jsonwebtoken');
const token = jwt.sign({ sub: '123' }, 'secret', { expiresIn: '1h' });
const data = jwt.verify(token, 'secret');
常见问题(FAQ)
Q:JWT 和 Session 有什么区别?
A:Session 在服务端存储状态(内存或数据库),客户端只存 Session ID。JWT 是无状态的——服务端不存储,所有信息都在 Token 本身。JWT 的优势是横向扩展容易(无需共享 Session 存储),劣势是无法主动失效(除非维护黑名单)。
Q:JWT 应该存储在哪里?
A:有两种方案:localStorage(易遭受 XSS 攻击,但不受 CSRF 影响);HttpOnly Cookie(XSS 无法访问,但需要处理 CSRF)。一般推荐 HttpOnly Cookie + CSRF Token 的组合。
Q:如何让 JWT 提前失效?
A:JWT 设计上是无状态的,没有内置的撤销机制。常用解决方案:维护 Token 黑名单(数据库或 Redis);使用短过期时间(如 15 分钟)配合 Refresh Token;修改用户的 secret 版本号使旧 Token 失效。