1. 简介
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
2. 构成
分为三个部分,分别为header/payload/signature。其中header是声明的类型和加密使用的算法。payload是载荷,最后是加上HMAC(base64(header)+base64(payload), secret)
3. 安全问题
3.1. Header部分
- 是否支持修改算法为none/对称加密算法
- 删除签名
- 插入错误信息
- 直接在 header 中加入新的公钥
- kid字段是否有SQL注入/命令注入/目录遍历
- 结合业务功能通过kid直接下载对应公私钥
- 是否强制使用白名单上的加密算法
- JWKS 劫持
- JKU (JWK Set URL) / X5U (X.509 URL) 注入
在渗透测试中,JWT(JSON Web Token)的Header部分漏洞是现代无状态认证系统中最常见且最致命的高危逻辑弱点之一。即使系统使用了JWT,Header被误配置或未严格校验的情况在微服务、API网关、SaaS、移动端后台、OAuth/OpenID系统中仍高发。Header作为算法声明和扩展参数载体,一旦被攻击者操控,可直接导致算法降级、签名绕过、密钥泄露、任意用户伪造登录(含管理员提权)。
| 漏洞类型 | 典型触发方式 | 危害后果 | 修复建议(加固方向) |
|---|---|---|---|
| 支持alg=none算法 | 将header中"alg":"none",删除签名部分(. .)提交 | 无需密钥即可伪造任意JWT,直接登录任意用户 | 后端明确拒绝alg=none + 校验签名必须存在且有效 |
| 算法混淆/降级(none或对称) | 原RS256改为HS256(公钥当对称密钥),或直接改alg为HS256/PS256等 | 用公钥作为对称密钥验证签名,伪造任意Token | 强制白名单算法(仅允许预期算法)+ 区分非对称/对称密钥类型 |
| 删除签名部分 | 保留header和payload,签名部分留空或删除(.. 或 .) | 绕过签名校验,直接使用无签名JWT | 后端必须严格校验三段结构 + 签名不能为空且验证通过 |
| Header插入错误/恶意信息 | 在header中插入"exp"超长未来时间、"jti"重复、"iss"伪造等干扰字段 | 绕过过期校验、重放攻击、issuer伪造 | Header只解析白名单字段(alg、typ、kid、jku等)+ 其他字段忽略或拒绝 |
| 直接在header加入新公钥(jwk) | header中嵌入{"jwk":{"kty":"RSA","n":...,"e":...}},声明自己的公钥 | 服务器使用攻击者提供的公钥验证签名 → 伪造任意Token | 禁止header内嵌jwk + 只信任预配置或JWKS端点公钥 |
| kid字段注入(SQLi/RCE/遍历) | kid参数指向可控路径(如../../../etc/passwd)或SQL语句 | 目录遍历读取任意文件、SQL注入、命令注入泄露密钥 | id |
| kid结合业务下载公私钥 | kid指向服务器上可下载的密钥文件路径(如kid=/path/to/private.key) | 直接下载私钥 → 离线伪造任意管理员JWT | 密钥文件禁止Web访问 + kid路径规范化 + 未授权返回404/403 |
| 未强制算法白名单 | 支持任意alg(如HS256、RS256、ES256随意切换) | 算法降级攻击、混淆攻击成功率极高 | 后端硬编码只接受指定算法(if alg not in ['RS256'] reject) |
| JWKS劫持(.well-known误配) | JWKS端点未防护、缓存投毒、DNS劫持导致加载恶意JWKS | 服务器加载攻击者控制的JWKS公钥 → 伪造Token | 固定本地JWKS或可信源 + 禁止动态jku + 证书校验 |
| JKU/X5U注入 | header中jku或x5u指向攻击者控制的URL,服务器去该URL拉取公钥或证书 | 服务器加载攻击者公钥/证书 → 伪造任意JWT | 禁止jku/x5u或严格白名单 + SSRF防护 + HTTPS证书校验 |
3.1.1JWT Header
alg=none + 删除签名
最经典,直接无签名JWT登录管理员 → 一键接管全站。RS256→HS256混淆 + 公钥当密钥
抓公钥证书 → base64url(n)作为HS256密钥 → 伪造admin JWT。kid路径遍历 + 私钥泄露
kid=../../../../app/keys/private.pem → 响应直接返回私钥 → 离线无限签管理员Token。jku注入 + 自控JWKS
jku=https://attacker.com/jwks.json → 服务器加载攻击者公钥 → 用对应私钥签任意用户。
3.1.2 Burp测试流程
抓取任意有效JWT(登录、刷新、API请求头Authorization: Bearer)
用Repeater+JWT Editor插件(Burp必备)快速测试:切换alg=none并删除签名
- RS256→HS256混淆(自动用公钥签名)
- 添加jwk嵌入自己公钥
- 修改kid为路径遍历payload(../../etc/passwd、|whoami|等)
- 设置jku/x5u为自控URL
用Intruder枚举kid常见路径:
- Payloads:常见密钥路径字典(/etc/jwt.key、/app/config/private.pem、../keys/id_rsa)
- Grep私钥特征(-----BEGIN RSA PRIVATE KEY-----)
工具辅助:
- jwt.io在线调试(本地离线)
- jwt_tool.py(2025最新版)一键扫描所有Header漏洞
3.2. Payload部分
- 其中是否存在敏感信息
- 检查过期策略,比如
exp,iat
在渗透测试中,JWT(JSON Web Token)的Payload部分是承载用户身份、权限、时效等核心声明的地方。Payload设计或校验不严仍是微服务、API网关、移动端认证、OAuth系统中高发漏洞区域。Payload虽不参与签名验证逻辑,但一旦泄露敏感信息或时效声明被绕过/伪造,可导致隐私大规模泄露、长期有效Token滥用、权限持久化提权等严重后果。
| 漏洞类型 | 典型触发方式 | 危害后果 | 修复建议(加固方向) |
|---|---|---|---|
| Payload中包含敏感信息 | 明文放置手机号、邮箱、身份证、地址、内部ID、权限列表、密钥片段等 | 任意接口泄露用户隐私,可用于社工、撞库、精准钓鱼 | Payload只放必要声明(sub、iss、aud、role、jti)+ 敏感信息加密或移到后端Session + 脱敏返回 |
| 过期策略缺失或弱(exp) | 无exp声明、exp设置过长(如多年)、exp可被篡改后仍通过 | Token长期有效,离线持久化登录,失窃后长期滥用 | 必须强制设置exp(建议15-60分钟)+ 后端严格校验当前时间 < exp + 结合刷新Token机制 |
| 签发时间校验缺失(iat) | 无iat或不校验iat,导致可伪造超旧Token重放 | 旧Token或提前生成的Token可长期使用 | 强制校验iat ≤ 当前时间 + 宽容漂移(≤300秒) |
| 不活跃过期缺失(nbf) | 无nbf或nbf可改成过去时间,使Token立即生效 | 提前生成的Token可立即使用 | 如需延迟生效必须设置nbf + 严格校验当前时间 ≥ nbf |
| Token唯一性缺失(jti) | 无jti或jti不加入黑名单,导致已注销/失效Token可重用 | 注销后旧Token仍有效,难以真正登出 | 使用jti作为唯一ID + Redis/MySQL黑名单 + 注销时加入 + 短生命周期 |
| 权限/角色字段可篡改 | Payload中role/scope/permissions字段未后端二次校验,可任意修改 | 垂直提权,普通用户伪造成管理员 | 权限必须后端独立校验(Session/DB)+ Payload角色仅作参考或不放 |
| iss/aud/sub可篡改绕过 | 发行者(iss)、受众(aud)、主体(sub)未严格校验或可伪造 | 跨域/跨服务Token盗用,伪造任意用户sub登录 | 后端硬编码校验iss/aud必须匹配预期 + sub绑定不可篡改用户ID |
| 自定义声明泄露业务信息 | 自定义字段如"balance"、"vip_level"、"internal_flag"等明文放置 | 泄露用户资产、等级、内部状态,便于针对性攻击 | 禁止Payload放置任何业务敏感数据 + 必要时加密声明 |
3.2.1 JWT Payload
敏感信息明文 + 任意接口泄露
Payload里直接放手机号+邮箱 → 所有API响应头都带JWT → 一抓包就脱裤全量用户隐私。exp超长/可篡改 + 无jti黑名单
把exp改到2030年 + 注销后旧Token仍有效 → 离线持久化管理员权限。role字段可改 + 无后端二次校验
普通用户把role改成"admin"重新签名 → 直接访问全量用户管理接口。sub可篡改 + iss/aud弱校验
sub改成管理员ID + iss改成假值 → 跨服务伪造管理员Token。
3.2.2 Burp测试流程
- 抓取任意有效JWT(登录返回、刷新Token、任意API Authorization头)
- 用Burp自带JWT Editor插件(必装)或Decoder解码Payload:
- 查看所有字段,标记敏感信息(手机号、权限、余额等)
- 检查exp/iat/nbf/jti是否存在及合理性
- 用Repeater+JWT Editor快速篡改测试:
- 修改exp为超长未来时间
- 修改role="admin"、sub="1"、iss/aud为假值
- 添加/删除jti、nbf字段
- 重新签名(用原密钥或已知密钥)发包
- 观察是否仍被接受并获得对应权限/数据
- 注销测试:
- 正常注销后,用旧JWT继续访问高权限接口 → 若成功 = 无jti黑名单或exp弱
3.3. Signature部分
- 检查是否强制检查签名
- 密钥是否可以爆破
- 是否可以通过其他方式拿到密钥
在渗透测试中,JWT Signature(签名)部分是JWT安全的最后一道防线,在实测中被攻破最频繁的致命区域。一旦签名校验缺失、密钥强度弱或密钥泄露,攻击者即可离线无限伪造任意用户(含管理员)JWT,直接接管全站或全量API权限。
| 漏洞类型 | 典型触发方式 | 危害后果 | 修复建议 |
|---|---|---|---|
| 完全不校验签名 | 后端未验证签名或直接信任客户端JWT | 无需任何密钥即可伪造任意Token | 必须使用库的verify_signature严格校验,任何异常直接拒绝 |
| 签名校验可绕过(空签名+alg=none已测) | 某些旧库在特定条件下跳过签名校验 | 同上,伪造任意管理员Token | 强制三段完整性 + 签名长度校验 + 拒绝空签名 |
| 对称密钥(HS256/HS384/HS512)强度弱/可爆破 | 密钥为弱密码、业务字段、配置项(如"secret"、"123456"、"myjwtkey") | 字典爆破/彩虹表拿到密钥 → 离线无限签管理员JWT | 对称密钥必须≥32字节高熵随机(256bit+)+ 定期轮换 + 禁止硬编码 |
| 密钥硬编码在前端/JS文件中 | 密钥直接写在JavaScript、Swagger、Git历史、移动端APK中 | 直接提取密钥 → 伪造任意Token | 绝不在前端暴露密钥 + 使用非对称算法(RS256/ES256)+ 后端专用密钥服务 |
| 密钥通过kid/config接口泄露 | kid指向可遍历路径、调试接口直接返回secret、日志打印密钥 | 直接拿到对称密钥或私钥 | 密钥永不放在Web可访问路径 + 禁用所有调试端点 |
| 私钥(RS256)泄露或弱密钥 | 私钥放在Git、备份文件、调试页面,或使用1024位以下弱RSA | 拿到私钥 → 无限签任意用户JWT | 使用≥2048位RSA或推荐ES256/P256 + 私钥必须离线存储 + 权限600 |
| 密钥轮换机制缺失导致旧密钥长期有效 | 系统支持历史密钥验证,旧密钥未失效 | 泄露的任意历史密钥都可长期使用 | 实现密钥版本+轮换 + 旧密钥只允许刷新新Token,不允许直接认证 |
| 签名算法与密钥类型不匹配仍通过 | RS256却用对称密钥验证,或反过来 | 结合Header混淆攻击直接成功 | 后端严格区分算法与密钥类型(RS用公钥,HS用对称密钥) |
JWT Signature
前端JS硬编码secret(最常见)
全局搜索“HS256”+“secret” → 找到密钥 → jwt.io一键签admin → 全站接管。弱密钥8-16位被秒破
jwt_tool 10万常用密钥字典 → 3秒出结果 → 离线批量签千万管理员Token。私钥通过kid遍历直接下载
kid=../../../../app/keys/private.pem → 响应直接返回-----BEGIN RSA PRIVATE KEY----- → 完蛋。不校验签名(极隐蔽)
某些微服务网关只解析Payload不验签 → 改签名成“iloveyou”照样管理员权限。
Burp测试流程
- 抓任意有效JWT → 扔进Burp JWT Editor插件
- 自动/手动三连击:
- 点“Sign”但故意填错密钥或空 → 发包看是否仍通过
- 改Payload role=admin → 签名随便填“123”发包
- 切换alg为HS256,用常见弱密钥(secret、123456、[项目名]+jwt)重新签名发包
- 用venom一键全扫描(推荐命令)【额外工具:Tscanplus无影、DudeSuite】:
3.4. 其他
- 重放
- 通过匹配校验的时间做时间攻击
- 修改算法RS256为HS256
- 弱密钥破解
| 漏洞类型 | 典型触发方式 | 危害后果 | 修复建议(加固方向) |
|---|---|---|---|
| JWT重放攻击(Replay Attack) | 同一个有效JWT在不同接口、不同会话、注销后仍可重复使用 | 注销失效、跨接口盗用、旧Token长期有效 | 强制使用jti唯一ID + Redis黑名单(注销/刷新时加入)+ 短exp(≤15分钟)+ 绑定设备指纹 |
| 时间校验弱导致定时攻击(Timing Attack) | 后端对exp/iat校验存在时间差异,或签名验证过程对密钥猜测有时间侧信道 | 暴力猜密钥、精确预测Token有效窗口 | 使用恒定时间比较算法(constant-time)+ 严格时间漂移(≤60秒)+ 异常直接拒绝不返回差异 |
| RS256→HS256算法混淆(重复经典但变种多) | 服务器同时支持RS和HS,但公钥与对称密钥存储方式混淆,或未区分算法类型 | 用公钥作为HS256对称密钥成功验证伪造Token | 后端严格区分算法类型(RS用RSA公钥,HS用secret)+ 强制单一算法白名单 + 拒绝混淆 |
| 弱密钥破解(综合爆破) | 对称密钥熵低、来源于配置/环境变量、常见密码、项目名拼接等 | 拿到密钥后离线无限伪造任意管理员JWT | 对称密钥必须≥256bit纯随机 + 使用密钥管理服务(Vault/KMS)+ 禁止任何可预测来源 |
| JWT存储不当导致窃取重用 | 前端localStorage/cookie无HttpOnly/Secure/SameSite,易被XSS窃取 | XSS一键偷全站JWT → 持久化接管账号 | Cookie必须HttpOnly + Secure + SameSite=Strict/Lax + 敏感Token短效+刷新机制 |
| 刷新Token机制弱导致无限续期 | Refresh Token无jti黑名单、无单点注销、无设备绑定 | 偷到Refresh Token可无限获取新Access Token | Refresh Token同jti黑名单 + 注销即失效 + 绑定设备/IP + 单独长效但可撤销 |
| JWT与Session混合校验不一致 | 部分接口用JWT,部分用Session,导致可单独使用JWT绕过Session注销 | 注销Session后JWT仍有效,单点登录失效 | 统一认证体系 + 注销时同时失效JWT(黑名单或短exp) |
作者申明:
1. 应遵守以下中华人民共和国法律法规制定:
《中华人民共和国网络安全法》
《中华人民共和国个人信息保护法》
《中华人民共和国数据安全法》
《关键信息基础设施安全保护条例》
2. 一定要在授权范围内使用:
合法授权测试:仅在获得目标系统所有者明确书面授权的情况下使用。
合规安全测试:用于提升系统安全防护能力为目的的渗透测试活动。
教育研究目的:在合法教育机构或研究机构内部使用。
应急响应:在网络安全事件应急响应中使用。