JWT 结构解析:Header、Payload、Signature 三部分详解
JWT(JSON Web Token)是一种紧凑、URL 安全的令牌表示方式,其结构由三个独立的部分组成:Header(头部)、Payload(载荷)和Signature(签名)。这三部分通过 Base64URL 编码后以点号(.)连接,形成形如 xxxxx.yyyyy.zzzzz 的字符串。理解每一部分的职责与安全边界,是构建可信 JWT 系统的第一步。
安全提示:JWT 的 Header 和 Payload 仅经过 Base64URL 编码,并非加密。任何持有令牌的人都可以解码并读取其内容。敏感信息(如密码、信用卡号)严禁放入 Payload。
2.1 Header(头部)—— 算法声明与类型标识
Header 是 JWT 的第一段,通常包含两个标准字段:令牌类型(typ)和签名算法(alg)。它告诉接收方如何验证该令牌的签名。
| 字段 | 含义 | 常见值 | 安全要点 |
|---|---|---|---|
alg |
签名或加密算法 | HS256、RS256、ES256 |
禁止使用 none;服务端必须白名单校验 |
typ |
令牌类型 | JWT |
通常固定为 JWT,可省略 |
kid |
密钥 ID(可选) | 字符串标识 | 用于多密钥场景,需防止注入攻击 |
一个典型的 Header 示例:
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-2024-01"
}
高危漏洞:alg=none 攻击 —— 若服务端未强制校验算法白名单,攻击者可将
alg 改为 none 并移除签名部分,伪造任意身份。务必在验证逻辑中拒绝 none 算法。
2.2 Payload(载荷)—— 声明与数据承载
Payload 是 JWT 的第二段,包含实际传递的声明(Claims)。声明分为三类:注册声明、公共声明和私有声明。Payload 的大小直接影响网络传输效率,建议控制在 1KB 以内。
| 声明类型 | 说明 | 标准字段示例 | 安全约束 |
|---|---|---|---|
| 注册声明 | 预定义的标准字段 | iss、sub、aud、exp、nbf、iat、jti |
服务端必须校验 exp、nbf、aud |
| 公共声明 | 公开定义的字段 | name、role、scope |
避免敏感信息;使用 IANA 注册名称 |
| 私有声明 | 自定义字段 | user_id、tenant |
命名冲突风险;建议加前缀 |
一个典型的 Payload 示例:
{
"iss": "https://auth.example.com",
"sub": "user_123456",
"aud": ["api.example.com", "admin.example.com"],
"exp": 1735689600,
"iat": 1735603200,
"jti": "unique-token-id-001",
"role": "admin",
"scope": "read write"
}
关键校验点:
exp(过期时间):必须校验当前时间是否在过期时间之前nbf(生效时间):当前时间必须晚于该时间aud(受众):必须校验接收方是否在受众列表中iss(签发者):必须与信任的签发者列表匹配
2.3 Signature(签名)—— 完整性保护与防篡改
Signature 是 JWT 的第三段,由 Header 中指定的算法对 Header + "." + Payload 进行签名生成。签名确保了令牌在传输过程中未被篡改,并验证了签发者的身份。
签名生成公式:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
对于非对称算法(如 RS256):
RSASHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
privateKey
)
| 算法类型 | 密钥管理 | 验证方 | 适用场景 |
|---|---|---|---|
| HS256(对称) | 单一共享密钥 | 持有密钥的任何方 | 单一服务、内部系统 |
| RS256(非对称) | 私钥签名,公钥验证 | 仅需公钥 | 微服务、第三方集成 |
| ES256(椭圆曲线) | 私钥签名,公钥验证 | 仅需公钥 | 移动端、IoT 设备 |
密钥泄露风险:对称算法(HS256)要求所有验证方持有相同的共享密钥,增加了密钥泄露面。在分布式系统中,优先使用非对称算法(RS256/ES256),仅签名方持有私钥,验证方只需公钥。
2.4 完整 JWT 结构示例
以下是一个完整的 JWT 令牌示例,展示了三部分如何组合:
// Header
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
.
// Payload
eyJzdWIiOiJ1c2VyXzEyMzQ1NiIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTczNTY4OTYwMH0
.
// Signature
Ew5Qp7YH9Mdq3R8vK2Lx4Zn6Bc1Df3Gh5Ij7Kl9Mn0Op2Qr4St6Uv8Wx0Yz1Ab3Cd5Ef7
结构总结:
- Header:算法声明 + 类型标识,Base64URL 编码
- Payload:声明数据(注册/公共/私有),Base64URL 编码
- Signature:对前两部分的签名,确保完整性和真实性
- 安全原则:Header 和 Payload 可读,敏感信息必须加密或仅放在 Signature 可验证的受信任方
2.5 常见安全陷阱与最佳实践
| 陷阱 | 风险描述 | 最佳实践 |
|---|---|---|
| alg=none | 攻击者移除签名,伪造任意令牌 | 服务端强制校验算法白名单,拒绝 none |
| 算法混淆 | 将 RS256 公钥作为 HS256 密钥使用 | 严格区分对称/非对称算法验证逻辑 |
| Payload 敏感信息 | Base64 解码即可读取,信息泄露 | 敏感数据使用 JWE 加密或仅存引用 |
| 过期时间缺失 | 令牌永久有效,无法撤销 | 必须设置 exp,建议短生命周期(15-60 分钟) |
| 密钥硬编码 | 密钥泄露导致整个系统被攻破 | 使用密钥管理服务(KMS)或环境变量 |
架构建议:在微服务架构中,建议使用非对称算法(RS256/ES256),由认证服务持有私钥签发令牌,其他服务仅持有公钥验证。这样即使某个服务被攻破,攻击者也无法签发新令牌。