JWT渗透测试终极实战指南

在现代 Web 应用与微服务架构中,JSON Web Token (JWT) 已经成为身份验证与授权的标准配置。然而,开发者在实现 JWT 机制时,常常因过于依赖库的默认配置或对加密签名理解不足,引入严重的安全漏洞。

1. JWT 结构速览与测试切入点

一个标准的 JWT 由三部分组成,用点号 (.) 隔开:Header.Payload.Signature

复制代码
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

在测试开始前,使用 base64url 解码前两部分,重点关注以下关键字段:

字段 属于 作用与测试切入点
alg Header 签名算法(关键攻击点:none 绕过、密钥混淆、弱算法)
jku / jwk Header 动态密钥/公网密钥检索 URL(关键攻击点:SSRF、任意密钥注入)
kid Header 密钥标识符 Key ID(关键攻击点:SQLi、目录遍历、命令注入)
exp / nbf Payload 过期时间 / 生效时间(关键攻击点:Token 永久有效、重放攻击)
role / admin Payload 用户权限声明(关键攻击点:未验证签名时的垂直越权)

2. JWT 核心攻击向量与实战思路

向量一:客户端未验证签名 (Unverified Signature)

这是最低级但也最常见的实现错误。部分开发者在后端仅使用了 jwt.decode() 提取 Payload 数据,而未调用 jwt.verify() 校验签名。

  • 测试方法

    1. 截获合法 JWT,解码 Payload。

    2. 修改 Payload 中的身份数据(例如将 "user_id": 102 改为 "user_id": 1"is_admin": true)。

    3. 保留原签名或直接删除签名发送请求。

  • 判定结果:若接口成功返回敏感数据或执行了管理员操作,即存在越权漏洞。

向量二:none 算法绕过 (None Algorithm Flaw)

JWT 规范允许设置 "alg": "none",表示该 Token 无需签名。如果后端验证库配置不当,会误将带有 none 算法的伪造 Token 视为合法。

  • 测试方法

    1. 修改 Header 中的 algnone(尝试变体:None, NONE, nOnE)。

    2. 修改 Payload 中的权限数据。

    3. 移除最后的 Signature 部分 (但必须保留末尾的点号 .,即 Header.Payload.)。

  • 自动化 PoC 脚本(Python)

    import base64
    import json

    header = {"alg": "none", "typ": "JWT"}
    payload = {"sub": "admin", "admin": True}

    def b64_encode(data):
    return base64.urlsafe_b64encode(json.dumps(data).encode()).decode().rstrip("=")

    jwt_none = f"{b64_encode(header)}.{b64_encode(payload)}."
    print("PoC JWT:", jwt_none)

向量三:对称加密弱密钥爆破 (Weak HMAC Secret)

在使用 HS256 (HMAC-SHA256) 等对称加密算法时,签名和验签使用的是同一个密钥(Secret)。如果开发者设置的 Secret 过短或属于常用字典词汇,攻击者可直接离线爆破。

  • 实战工具:Hashcat

    1. 将获得的完整 JWT 存入 jwt.txt

    2. 使用 Hashcat 进行字典爆破:

      复制代码
      hashcat -m 16500 jwt.txt rockyou.txt
    3. 一旦爆破出密钥(如 secret123),即可在本地使用该密钥对任意伪造的 Payload 重新签名,实现完全接管。

向量四:算法混淆攻击 (Algorithm Confusion / Key Confusion)

这是 JWT 密码学攻击中最经典的一类。漏洞起源于:服务端本应使用 RS256 (非对称加密:私钥签名,公钥验签),但攻击者强行将 Header 改为 HS256(对称加密)。

  • 原理

    • RS256 下,服务器会在本地存储一个公钥 public.pem 用于验签。

    • 若服务器把算法误当作 HS256 处理,它会把 public.pem文件文本内容当成对称加密的 HMAC Secret。

    • 因为公钥通常是公开的(例如可以通过 /.well-known/jwks.json 或前端静态文件直接获取),攻击者可以使用该公钥作为 HMAC 密钥在本地签发恶意 Token!

  • 攻击步骤

    1. 获取目标的公开公钥文件(如 public.pem)。

    2. 修改 Header 中的 "alg": "HS256"

    3. 修改 Payload(如提权为 admin)。

    4. 使用 public.pem 文本字符串 作为密钥,用 HS256 算法对 Token 进行签名。

向量五:Header 参数注入 (Header Parameter Injections)

JWT Header 中的部分可选参数具备强大的解析能力,若后端处理不当,会引入额外的漏洞链:

1. kid (Key ID) 注入

kid 用于指定服务器数据库或文件系统中对应密钥的 ID。

  • 目录遍历 (Path Traversal) :若后端通过 kid 拼接文件路径读取密钥,可构造 "kid": "../../../../../dev/null",此时密钥内容为空(""),攻击者可用空字符串签名 Token。

  • SQL 注入 :若 kid 从数据库查询密钥,可构造 "kid": "key1' UNION SELECT 'my_secret'--",将密钥强制指定为 my_secret

  • 命令注入 :若 kid 传入了系统命令处理函数,可尝试 ; command injection

2. jku (JWK Set URL) Header 伪造

jku 允许 Token 指定获取公钥的远程 URL。

  • 攻击方式 :攻击者在自己的服务器上挂载恶意 jwks.json,并将 Token Header 中的 jku 修改为 [https://evil.com/jwks.json](https://evil.com/jwks.json)。若后端未对 jku 域名做白名单校验,就会读取攻击者的公钥来验证攻击者伪造的 Token。

  • 延伸攻击 :若服务端开启了域名校验但校验逻辑不严,可尝试 SSRF、URL 绕过(如 [https://trust.com@evil.com](https://trust.com@evil.com))等。

向量六:生命周期与重放攻击 (Token Lifetime & Revocation)

  • 永不过期 :检查 Payload 中的 exp 字段是否存在。若不存在,说明 Token 永久有效。

  • 修改过期时间 :尝试将 exp 修改为未来的时间戳,观察服务器是否仍接收签名未变的修改版(验证是否做过签名校验)。

  • 注销不失效 (Lack of Blacklist):在前端点击"注销/退出登录"后,提取注销前的旧 Token 再次发送请求。若仍能访问,说明后端未建立有效的 Token 黑名单机制(如 Redis 缓存注销 Token)。

3. JWT 渗透测试标准 Checklist

在针对 JWT 进行黑盒/白盒测试时,可按照以下流程图进行快速排查:

4. 防御与安全修复方案

要彻底修复 JWT 相关漏洞,开发团队应遵循以下防护原则:

  1. 强强制签名校验 :永远不要依赖 JWT Header 传入的 alg 参数。后端代码必须显式写死期望使用的算法(例如强制限制为 RS256)。

  2. 严禁使用 none 算法 :在 JWT 解析库中禁用 none 算法支持。

  3. 保障密钥强度与安全

    • 对称加密(HS256)必须使用至少 256 位(32 字节)的高熵随机密钥。

    • 非对称加密(RS256)应妥善保管私钥,公钥校验时严格限定算法类型。

  4. 严格校验 Header 参数 :若使用 jku,必须建立严格的 URL 白名单;若使用 kid,必须进行严格的净化(Sanitize)与参数化查询,防止路径遍历或 SQL 注入。

  5. 完善注销机制:结合 Redis 等内存数据库建立 Token 黑名单(或短生存周期 + Refresh

相关推荐
2401_894915533 小时前
GEO 定位优化源码搭建常见报错排查:数据库、伪静态、接口调试
java·数据库·网络协议·tcp/ip·spring·unity
程序猿乐锅3 小时前
【计算机网络 | 第四章】网络层
网络·计算机网络·智能路由器
奇树谦3 小时前
《现代 Key-Value 数据库原理:从 B+Tree 到 LSM Tree》-第三篇:LMDB 深度解析二
数据库·oracle·lsm-tree
提笔了无痕3 小时前
Agent 上下文管理详解、Context设计与构建
数据库·oracle·agent·context
用户7152287381413 小时前
数据库字段冗余,真的只是用空间换时间吗?
数据库
沉下去,苦磨练!3 小时前
Human‑in‑the‑Loop
数据库·oracle
z20348315203 小时前
Ubuntu双系统安装指南:从 UEFI 原理到 Ubuntu 分区方案的全面解析
linux·运维·ubuntu
吠品3 小时前
Java中实现拓扑排序的两种方式:Kahn算法和DFS
java·数据库·notepad++
轻揉小乔 真新人3 小时前
数据库架构的升级和变更
数据库·数据库架构
2401_873479404 小时前
IP地址位置精确查询的原理是怎样的?从城市级到街道级的技术拆解
网络·网络协议·tcp/ip·ip