JSON Web Token (JWT) 安全详解
字数 1785 2025-11-13 09:24:33
JSON Web Token (JWT) 安全详解
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用间安全传递声明(如用户身份信息)。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature),通过点号(.)分隔,形式为Header.Payload.Signature。虽然JWT被广泛用于身份验证和授权,但若实现不当,可能导致严重的安全漏洞。
1. JWT的结构与工作原理
(1)头部(Header)
- 作用:描述令牌类型(如JWT)和签名算法(如HMAC、RSA)。
- 示例:
{ "alg": "HS256", // 算法为HMAC-SHA256 "typ": "JWT" } - Base64编码后:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9。
(2)载荷(Payload)
- 作用:携带实际声明(例如用户ID、角色、过期时间)。
- 声明类型:
- 标准声明:如
exp(过期时间)、iss(签发者)。 - 公共声明:预定义但需避免冲突的字段。
- 私有声明:自定义业务字段(如
"username": "alice")。
- 标准声明:如
- 示例:
{ "sub": "1234567890", "name": "Alice", "admin": true } - Base64编码后:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiYWRtaW4iOnRydWV9。
(3)签名(Signature)
- 作用:验证令牌完整性,防止篡改。
- 生成方式(以HS256为例):
Signature = HMACSHA256(Base64(Header) + "." + Base64(Payload), secret_key) - 最终JWT:将三部分用点连接,例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiYWRtaW4iOnRydWV9.Signature
2. JWT的常见安全风险
风险1:算法切换攻击("alg"字段篡改)
- 原理:JWT支持多种签名算法(如HS256对称加密、RS256非对称加密)。若攻击者将头部中的
alg改为none(无签名)或从非对称算法(RS256)改为对称算法(HS256),可能绕过签名验证。 - 攻击步骤:
- 拦截合法JWT,将头部改为
{"alg":"none","typ":"JWT"}。 - 删除签名部分(因
alg:none无需签名),形成Header.Payload.。 - 若服务器未严格校验算法,会接受此令牌。
- 拦截合法JWT,将头部改为
- 防御:在代码中强制校验
alg字段,禁止使用none算法,并确保非对称加密场景下不使用对称密钥验证。
风险2:密钥泄露或弱密钥
- 原理:对称算法(如HS256)依赖共享密钥。若密钥强度弱(如常见字典词)或泄露,攻击者可伪造任意令牌。
- 示例:使用弱密钥
secret时,攻击者可通过工具(如jwt_tool)暴力破解密钥。 - 防御:使用强随机密钥(如32字节以上),定期轮换密钥,避免硬编码在代码中。
风险3:未验证签名
- 原理:部分开发者在测试阶段可能跳过签名验证,若此逻辑误上线,攻击者可随意修改Payload。
- 防御:始终在服务端验证签名,并使用标准库(如Java的
jjwt、Python的PyJWT)。
风险4:敏感信息泄露
- 原理:JWT的Payload仅经过Base64编码(非加密),若传输敏感数据(如密码、密钥),可能被中间人窃取。
- 防御:避免在Payload中存放敏感信息,全程使用HTTPS传输。
风险5:令牌泄露与重放攻击
- 原理:若JWT被窃取(如通过XSS),攻击者可在有效期内重复使用它。
- 防御:
- 设置短过期时间(如15分钟)。
- 使用刷新令牌(Refresh Token)机制。
- 结合IP绑定或令牌黑名单。
3. JWT安全实践建议
- 算法选择:优先使用非对称算法(如RS256),私钥由签发方保存,公钥用于验证。
- 校验完整性:验证签名、过期时间(
exp)、签发者(iss)等字段。 - 存储安全:JWT在客户端应存于
HttpOnly的Cookie中(防XSS),避免LocalStorage。 - 工具辅助:使用官方库自动处理编码/解码,避免手动实现。
4. 实战案例:算法切换攻击复现
- 原始JWT(使用RS256算法):
Header: {"alg":"RS256","typ":"JWT"} Payload: {"user":"admin","exp":1672531200} - 攻击修改:
- 将头部改为
{"alg":"HS256","typ":"JWT"}。 - 使用服务器的RS256公钥作为HS256的对称密钥,伪造签名。
- 将头部改为
- 结果:若服务器错误地用公钥验证HS256签名,会接受此恶意JWT。
通过以上分析,JWT的安全性高度依赖实现细节。开发者需严格遵循最佳实践,避免常见配置错误。