本文目录导读:

JWT(JSON Web Token)防止伪造的核心机制主要依赖于签名验证和防篡改设计,以下是具体的防护机制和最佳实践:
核心防线:数字签名
JWT 由三部分组成:Header.Payload.Signature,防止伪造的关键在于第三部分——签名。
-
工作原理: 服务器在签发 JWT 时,会将
Header和Payload拼接起来,然后使用一个服务器端独有的密钥(Secret),通过指定的加密算法(如 HS256)生成一个签名,附加在令牌末尾。 -
防伪机制: 当客户端将 JWT 发送回服务器时,服务器会使用同样的密钥和算法,对
Header和Payload重新计算签名,然后与 JWT 携带的签名进行比对。- 如果匹配:证明令牌在传输过程中未被篡改,且是由知道密钥的服务器签发。
- 如果不匹配:服务器立即拒绝该请求。
关键点:攻击者不知道服务器端的密钥,无法生成一个合法的签名,如果攻击者篡改了 Payload(比如将 userId 从 “123” 改成 “456”),服务器重新计算的签名会与原来的签名不一致,导致验证失败。
两种主流签名算法
| 算法类型 | 算法示例 | 密钥管理 | 适用场景 | 安全性关键 |
|---|---|---|---|---|
| 对称加密 | HS256 (HMAC + SHA256) | 共享密钥(Secret),签发和验证都使用同一个密钥。 | 单服务器或内部微服务(链路可信)。 | 密钥绝对不能泄露,一旦泄露,任何人都可以伪造任意用户的 JWT。 |
| 非对称加密 | RS256 (RSA + SHA256) ES256 (ECDSA + SHA256) |
公钥/私钥对。私钥用于签发(只在认证服务器保存),公钥用于验证(可分发到任何资源服务器)。 | 多服务架构、分布式系统、第三方应用集成。 | 私钥的安全是关键,公钥可以公开,但私钥必须严格保护,即使公钥泄露,攻击者也无法伪造签名。 |
为什么推荐 RS256/ES256?
- 资源服务器只需要公钥,不需要接触私钥,降低了密钥泄露的风险。
- 即使一个资源服务器被攻破,攻击者拿到公钥也无法签发新的 JWT。
其他关键防伪和安全性措施
仅仅依赖签名还不够,还需要配合以下措施:
a. 签名算法白名单
- 漏洞示例:攻击者将 JWT 的
alg字段从"RS256"改为"none"(无签名算法)。 - 防护:必须在服务器端代码中明确指定允许的签名算法列表,并拒绝任何
alg: none的令牌,否则,攻击者可以绕过签名验证。
b. 短有效期(Expiration Time, exp)
- JWT 的 Payload 应包含
exp字段。 - 原理:即使 JWT 被截获,攻击者只能在很短的时间内使用它(15 分钟或 1 小时)。
- 最佳实践:使用 Access Token(短期) + Refresh Token(长期) 的模式,用户频繁刷新短期令牌,降低长期令牌的暴露风险。
c. 禁用一个已泄露的 JWT(黑名单/Revocation)
- JWT 本身是无状态的,一旦签发,在过期前无法被服务器直接注销,但可以通过建立黑名单来模拟撤销。
- 如何做:当用户登出或怀疑令牌泄露时,服务器将该 JWT 的
jti(JWT ID) 存入一个短生命周期的黑名单(如 Redis),服务器每次验证 JWT 时,先检查它是否在黑名单中。 - 注意:这会增加服务器端状态,破坏了 JWT 完全无状态的优势,但有时是必要的。
d. 防止重放攻击
- 手段:在 Payload 中包含
jti(唯一标识符) 和iat(签发时间),并记录已使用过的jti,确保同一个 JWT 不能被多次使用。 - 适用场景:对幂等性要求极高的操作(如付款)。
e. 敏感信息不要放在 Payload 中(但这不是防伪造)
- JWT 的 Payload 是 Base64 编码,而非加密,任何拿到令牌的人都可以解码读取。
- 虽然这不直接导致伪造,但泄露敏感信息(如密码、手机号)会放大安全风险。永远不要在 Payload 中存放密码、信用卡号等核心敏感信息。
完整的防伪流程
- 用户登录:服务器验证身份后,使用私钥(RS256)签发 JWT。
- 后端验证:
- Step 1:解码 Base64 的 Header,获取
alg字段,检查是否在算法白名单中(拒绝none)。 - Step 2:检查
exp(过期时间) 和nbf(生效时间,可选) 是否有效。 - Step 3(可选):检查
jti是否在黑名单中。 - Step 4:使用公钥对 Header + Payload 重新计算签名,并与 JWT 携带的签名比对。
- 全部通过:请求合法,执行后续逻辑。
- 任一失败:返回 401 Unauthorized。
- Step 1:解码 Base64 的 Header,获取
一句话总结:JWT 通过对 Header 和 Payload 进行数字签名来防止伪造,只要服务器端的密钥(私钥)安全、签名算法不被绕过(如禁用 alg: none),并结合有效期和黑名单机制,JWT 就是安全的。