文章目录
- 前言
- [1. JWT基础与漏洞概述](#1. JWT基础与漏洞概述)
- [2. JWT核心漏洞解析](#2. JWT核心漏洞解析)
-
- [2.1 未校验签名](#2.1 未校验签名)
-
- [2.1.1 漏洞原理](#2.1.1 漏洞原理)
- [2.1.2 利用方式](#2.1.2 利用方式)
- [2.1.3 实战脚本](#2.1.3 实战脚本)
- [2.2 算法篡改漏洞](#2.2 算法篡改漏洞)
-
- [2.2.1 漏洞原理](#2.2.1 漏洞原理)
- [2.2.2 核心说明](#2.2.2 核心说明)
- [2.2.3 攻击流程](#2.2.3 攻击流程)
- [2.3 弱密钥漏洞](#2.3 弱密钥漏洞)
-
- [2.3.1 漏洞原理](#2.3.1 漏洞原理)
- [2.3.2 利用方式](#2.3.2 利用方式)
- [2.4 垂直越权](#2.4 垂直越权)
-
- [2.4.1 漏洞原理](#2.4.1 漏洞原理)
- [2.4.2 利用流程](#2.4.2 利用流程)
- [2.5 KID字段注入](#2.5 KID字段注入)
-
- [2.5.1 触发条件](#2.5.1 触发条件)
- [2.5.2 四类利用方式](#2.5.2 四类利用方式)
- [3. 漏洞防御建议](#3. 漏洞防御建议)
- [4. 总结](#4. 总结)
⚠️本博文所涉安全渗透测试技术、方法及案例,仅用于网络安全技术研究与合规性交流,旨在提升读者的安全防护意识与技术能力。任何个人或组织在使用相关内容前,必须获得目标网络 / 系统所有者的明确且书面授权,严禁用于未经授权的网络探测、漏洞利用、数据获取等非法行为。
前言
在当今的Web开发中,JSON Web Token(JWT)作为身份认证与授权的常用凭证,广泛应用于前后端分离、微服务等架构。然而,由于服务端配置不当、算法使用不规范等原因,JWT容易出现多种漏洞,被攻击者利用来实现越权访问或伪造身份。
1. JWT基础与漏洞概述
JWT由Header(头部)、Payload(载荷)、Signature(签名)三部分构成,主要用于实现无状态的身份验证。正常情况下,服务端通过校验签名来确认JWT的完整性与合法性。但如果校验逻辑存在缺陷,攻击者就能够通过篡改凭证、破解密钥等手段绕过认证,获取未授权的访问权限。
2. JWT核心漏洞解析
2.1 未校验签名
2.1.1 漏洞原理
服务端存在两种致命缺陷:一是完全不校验JWT的签名部分,直接信任Payload中的内容;二是允许使用alg: none无签名算法,该算法规定JWT无需进行签名校验,仅需保证格式正确即可通过验证。这两种情况均允许攻击者任意篡改Payload中的用户ID、权限等核心信息,实现身份伪造。
2.1.2 利用方式
- 修改JWT头部(Header),将算法指定为
none,即"alg": "none"; - 篡改Payload中的关键字段,如将普通用户ID(
sub: "10086")改为管理员ID(sub: "1"),调整过期时间(exp)延长凭证有效期; - 清除签名部分(JWT最后一个
.后面的内容留空),提交篡改后的JWT即可绕过认证。
2.1.3 实战脚本
以下Python脚本可直接构造None算法的恶意JWT,可根据目标系统调整Payload字段:
python
import time
import jwt
def forge_jwt_none_attack(exp_offset=3600):
"""
构造 JWT None 算法攻击的 Token
:param exp_offset: 过期时间偏移(秒),默认1小时
:return: 构造好的 JWT Token
"""
header = {
"typ": "JWT",
"alg": "none"
}
# Payload
now = int(time.time())
payload = {
"exp": now + exp_offset, # 过期时间
"iat": now, # 签发时间
"iss": "echisan",
"sub": "业务参数",
}
# 生成 JWT:key=None, algorithm=None
try:
jwt_token = jwt.encode(
payload,
key=None,
algorithm=None,
headers=header
)
except TypeError:
jwt_token = jwt.encode(
payload,
key="", # 部分旧版本需要传空字符串
algorithm="none",
headers=header
)
# 处理编码
if isinstance(jwt_token, bytes):
jwt_token = jwt_token.decode("utf-8")
return jwt_token
if __name__ == "__main__":
forged_token = forge_jwt_none_attack()
print(forged_token)
2.2 算法篡改漏洞
2.2.1 漏洞原理
正常业务使用RS256非对称算法签名,服务器持有私钥进行签名,并对外公开公钥用于验签。该漏洞的根源在于服务端不硬编码指定验签算法,而是直接读取JWT头部的alg字段来动态选择验签方式。攻击者将头部的alg:RS256篡改为alg:HS256,然后利用服务器公开的RSA公钥直接作为HS256的对称密钥,自行完成签名伪造。服务端读取alg为HS256后,会误用公钥当作对称密钥完成验签,从而直接放行恶意Token。
2.2.2 核心说明
- 服务器拥有私钥,为何不用私钥验签?
RS256规范规定只能用公钥验签,私钥仅负责签名,验签流程全程不会使用私钥,这是协议的固有规则。 - 为何会用公钥当做HS256密钥?
这是由于程序逻辑存在缺陷:只判断alg字段,不设置算法白名单进行拦截。当切换为HS256对称验签后,直接复用原有传入的公钥作为对称密钥,导致验签失效。
2.2.3 攻击流程
- 抓取正常业务JWT,获取服务器对外暴露的RSA公钥;
- 修改Header内
alg值,由RS256改为HS256; - 篡改Payload内用户ID、权限、角色等敏感字段;
- 使用服务器公钥作为HS256密钥重新生成签名;
- 携带伪造Token请求接口,服务端成功验签通过,实现身份伪造。
2.3 弱密钥漏洞
2.3.1 漏洞原理
JWT使用对称加密算法(如HS256)时,服务端会使用固定密钥对JWT进行签名与校验。若该密钥强度极低,攻击者可通过暴力破解的方式获取密钥,进而伪造任意合法JWT。
2.3.2 利用方式
核心是通过工具爆破弱密钥,常用工具推荐:TscanPlus(TideSec开源工具):集成JWT弱密钥破解功能,支持自定义字典,操作便捷,可直接联动其他功能进行后续攻击;破解密钥后,即可使用该密钥签名任意篡改后的Payload,生成合法JWT。
2.4 垂直越权
2.4.1 漏洞原理
垂直越权并非JWT自身的算法漏洞,而是基于上述两种漏洞(未校验签名、弱密钥)的衍生攻击。攻击者通过伪造高权限用户的JWT凭证,绕过服务端的权限控制,访问原本只有管理员等高级角色才能访问的接口或资源。
2.4.2 利用流程
- 通过无签名攻击或弱密钥爆破,获取伪造高权限JWT的能力;
- 篡改Payload中的权限字段(如
role: "admin"),生成高权限JWT; - 携带该JWT请求高权限接口(如
/admin/user/list、/system/setting),实现垂直越权访问。
2.5 KID字段注入
2.5.1 触发条件
JWT头部的kid(Key ID)字段用于指定服务端校验签名时使用的密钥(如密钥文件路径、数据库中的密钥ID)。若服务端未对kid字段进行过滤,直接将其拼接至密钥读取、查询逻辑中,攻击者可通过注入恶意内容,实现SQL注入、命令执行、文件读取等攻击。
2.5.2 四类利用方式
- SQL注入
核心思路:通过kid字段注入SQL语句,篡改密钥查询结果,让服务端使用攻击者指定的密钥进行签名校验。示例注入语句:xxx_key' UNION select'mykey' from INFORMATION_SCHEMA.SYSTEM_USERS --,关键注意点:xxx_key必须是不存在的密钥(确保UNION查询生效);mykey为攻击者指定的密钥,可根据需求进行Base64编码,增强隐蔽性。此外,还可结合布尔盲注、时间盲注,获取服务端数据库中的真实密钥。 - 命令注入
适用场景:服务端使用Ruby等语言,通过open函数读取密钥文件时,kid字段可拼接命令。测试方式:在kid字段中注入命令拼接内容,如kid: "key|whoami",若服务端执行该命令,可获取服务器权限。该场景较为少见,主要出现在配置不规范的Ruby项目中。 - 文件读取
- 路径穿越读取密钥 :通过
kid字段注入路径穿越字符,读取服务端本地的密钥文件,如kid: "../../../../../etc/passwd"(读取系统用户信息)、kid: "../../../../../var/www/secret.key"(读取应用密钥文件); - 空密钥利用 :注入
kid: "../../../../../dev/null",让服务端读取空文件作为密钥,此时可使用空密钥签名JWT,实现伪造。
3. 漏洞防御建议
针对上述漏洞,从开发与运维角度给出以下防御措施,避免JWT被滥用:
- 严格校验签名:禁止使用
alg: none算法,服务端必须校验JWT的签名完整性,不信任未签名或签名无效的凭证;明确指定验签算法,避免动态读取alg字段导致算法篡改漏洞。 - 强化密钥安全:使用对称加密算法时,采用高强度密钥(至少16位随机字符串),定期更换密钥;优先使用非对称加密算法(如RS256),私钥严格保管,不对外泄露。
- 过滤危险字段:对JWT头部的
kid等字段进行严格过滤,禁止特殊字符(如'、"、|、../),避免注入攻击。 - 限制Payload权限:Payload中不存储敏感信息(如密码、密钥),权限字段(如role)需在服务端二次校验,不依赖JWT中的内容。
- 缩短凭证有效期:合理设置JWT的
exp(过期时间),建议不超过1小时,降低凭证泄露后的风险。
4. 总结
JWT漏洞的产生主要源于服务端校验逻辑不严谨、配置不当。攻击者利用篡改凭证、破解密钥、注入攻击等手段,绕过身份认证与权限控制。
对于安全从业者,可借助本文内容快速识别JWT漏洞,开展渗透测试。后续可结合具体项目场景,深入研究JWT的进阶攻击方式,进一步提升安全防护能力。
本文是「Web安全基础」系列内容,点击专栏导航查看全部系列内容。