1. 项目概述为什么JWT攻击是Web安全测试的必修课如果你是一名Web安全测试人员或渗透测试爱好者那么“JWT攻击”这个词你一定不陌生。它就像一把双刃剑一方面JSON Web TokenJWT因其无状态、自包含的特性成为现代Web应用身份认证的主流方案另一方面如果开发者对其实现不当它又会成为攻击者绕过认证、垂直越权甚至接管账户的绝佳跳板。我见过太多项目前端界面做得光鲜亮丽后端逻辑也足够复杂但偏偏在JWT这个看似简单的“令牌”上栽了跟头导致整个认证体系形同虚设。这次我们不谈枯燥的理论直接上手实战。我将结合BurpSuite这款渗透测试“瑞士军刀”以及PortSwiggerBurpSuite官方出品的权威靶场为你完整拆解5种最常见、也最致命的JWT攻击手法。这不仅仅是“通关指南”更是一份从攻击者视角理解JWT安全缺陷的“内功心法”。无论你是想系统学习Web安全还是准备面试中的安全测试环节或是想加固自己开发的应用这里的内容都能让你获得立竿见影的提升。我们会从最基础的JWT结构讲起一步步深入到如何利用BurpSuite的JWT Editor插件篡改令牌、如何暴力破解弱密钥、如何利用算法混淆绕过验证最终实现权限提升。整个过程我会穿插大量我在实际测试和CTF比赛中踩过的坑和总结的技巧确保你不仅能“复现”更能“理解”和“举一反三”。2. 核心攻击手法原理与前置知识拆解在动手之前我们必须把“武器”和“靶子”都搞清楚。JWT攻击的核心在于理解其“自包含”和“可解码”的特性与服务器端验证逻辑之间的“信任间隙”。而BurpSuite和PortSwigger靶场则是我们演练这些攻击最理想的“训练场”。2.1 JWT结构三要素Header, Payload, Signature一个标准的JWT看起来像这样xxxxx.yyyyy.zzzzz由点号分隔的三部分组成。很多新手会直接把它当作一个加密的、不可读的字符串这是第一个误区。实际上JWT的前两部分Header和Payload仅仅是Base64Url编码的JSON对象任何人都可以轻松解码查看。Header头部通常包含令牌类型typ: “JWT”和所使用的签名算法alg如HS256HMAC SHA-256或RS256RSA SHA-256。这个alg字段是后续多种攻击手法的关键切入点。Payload负载包含了所谓的“声明”Claims也就是实际要传递的信息。常见声明有iss签发者、sub主题用户、exp过期时间、以及自定义的业务字段如username、admin、user_id等。攻击者的核心目标就是篡改这部分数据例如将username: “guest”改为username: “admin”。Signature签名这是JWT安全性的基石。服务器使用Header中指定的算法和一个密钥Secret Key或私钥对“Base64Url编码的Header” “.” “Base64Url编码的Payload”进行签名。签名的目的是验证消息在传输过程中未被篡改。服务器验证JWT的典型流程是收到令牌后用同样的密钥和算法重新计算签名并与令牌中的第三部分Signature进行比对。如果一致则认为令牌有效且未被篡改然后信任Payload中的数据。整个攻击逻辑都围绕“如何让服务器接受一个被我们篡改过Payload但签名验证仍能通过或绕过的JWT”而展开。2.2 攻击环境搭建BurpSuite与JWT Editor插件工欲善其事必先利其器。BurpSuite Professional是本次实战的核心工具社区版功能受限建议使用专业版。除了基本的Proxy代理、Repeater重放模块我们最关键的一个武器是“JWT Editor”插件。注意JWT Editor插件并非BurpSuite自带需要手动安装。你可以在BApp Store中搜索“JWT Editor”进行安装。安装后它会在Burp的多个标签页如Proxy历史、Repeater中增加一个“JSON Web Token”子标签方便你直接解码、编辑和重新签名JWT。为什么这个插件如此重要因为它将手动处理JWT的繁琐过程Base64编解码、JSON格式化、签名计算完全自动化了。在攻击过程中我们经常需要快速修改Payload中的某个字段比如把admin: false改成true然后尝试用不同的密钥或算法重新签名。没有这个插件你需要频繁切换解码网站和命令行工具效率极低且容易出错。有了它你可以在BurpSuite的界面内一键完成所有操作攻击流程变得行云流水。2.3 PortSwigger靶场理想的实战沙盒PortSwigger Web Security Academy网络安全学院的靶场是学习Web安全的黄金标准。它的JWT实验场景设计得非常精妙每一关都对应一种典型的JWT安全漏洞场景并且提供了真实的、有漏洞的Web应用环境。与DVWA、Pikachu等综合靶场不同PortSwigger的JWT实验目标单一干扰少非常适合专项突破。在开始前请确保你已经配置好BurpSuite并将浏览器代理指向Burp通常是127.0.0.1:8080。已安装并正确加载JWT Editor插件。访问PortSwigger官网找到“JWT attacks”模块下的实验Lab从第一个开始。每个实验都有明确的目标例如“绕过认证访问管理面板”或“以其他用户身份发布文章”。3. 5种核心JWT攻击手法实战解析下面我们进入正题逐一拆解这5种攻击手法。我会以PortSwigger靶场为背景详细说明攻击步骤、BurpSuite操作要点以及背后的原理。3.1 攻击手法一未验证签名——直接篡改Payload这是最基础但也最容易被忽视的一种漏洞。当服务器在验证JWT时根本没有检查签名部分或者验证逻辑存在缺陷例如只解码了Payload并使用了其中的数据但跳过了签名验证步骤。在这种情况下JWT的“签名”形同虚设。攻击原理由于Header和Payload只是Base64Url编码我们可以直接解码修改Payload中的关键信息如用户ID、角色权限然后重新编码拼接成一个新的、没有有效签名的令牌发送给服务器。服务器因为不验证签名会直接信任我们篡改后的数据。BurpSuite实战步骤拦截请求使用BurpSuite Proxy拦截一个包含JWT的HTTP请求通常在Authorization: Bearer JWT头或Cookie中。发送至Repeater右键点击请求发送到Repeater模块以便反复测试。解码与分析在Repeater中找到JWT所在的位置。如果安装了JWT Editor插件请求内容旁边会自动出现“JSON Web Token”标签页点击即可直观地看到解码后的Header和Payload。如果没有插件你可以复制xxxxx.yyyyy这部分到BurpSuite的Decoder模块进行Base64Url解码。篡改Payload在Payload部分找到标识用户身份或权限的字段。例如将sub: wiener普通用户修改为sub: administrator或carlos目标用户。或者将role: user修改为role: admin。重新编码与发送使用JWT Editor插件修改后它会自动更新整个JWT字符串。如果没有插件你需要手动将修改后的JSON进行Base64Url编码替换掉原来的yyyyy部分并保持第三部分签名zzzzz不变或直接删除如果服务器不检查。然后将这个篡改后的令牌放回原请求位置点击“Send”发送。观察响应如果服务器返回了成功访问目标资源如管理页面的响应则攻击成功。实操心得这种漏洞在实际中比想象中要多尤其是在一些快速开发、对安全不够重视的内部系统或早期版本中。测试时一个快速验证的方法就是直接删除JWT的第三部分签名只发送xxxxx.yyyyy.注意最后有个点看服务器是否依然接受。如果接受那问题就严重了。3.2 攻击手法二弱密钥爆破Brute-Force当JWT使用对称加密算法如HS256时服务器和客户端共享同一个密钥Secret来签名和验证。如果这个密钥强度不够例如是常见的单词、短字符串、或与项目名相关攻击者就有可能通过暴力破解的方式猜出密钥。攻击原理HS256签名本质上是一个带密钥的哈希HMAC。如果我们有了一段有效的JWT包含Header、Payload和Signature我们就可以尝试用一份常见的密钥字典如secret,password,123456, 项目名称等对已知的Header和Payload重新计算签名如果计算出的签名与原始JWT中的Signature一致那么就找到了正确的密钥。一旦获得密钥我们就可以为任意Payload生成合法的签名完全控制令牌。BurpSuite实战步骤结合Intruder模块获取样本令牌同样先拦截一个有效的JWT请求。使用JWT Editor插件爆破这是最高效的方法。在JWT Editor插件的“攻击”Attack选项卡中选择“对称密钥爆破”Brute-force secret。配置爆破参数将拦截到的JWT粘贴进去。你需要准备一个高质量的密钥字典。可以自己根据目标信息生成如公司名、项目名、常见弱口令也可以使用SecLists项目中的JWT-secrets.txt等专用字典。执行与识别点击开始插件会自动用字典中的每个密钥尝试对已知的Header和Payload进行签名并与原签名比对。爆破成功后插件会直接显示正确的密钥。利用密钥在JWT Editor的“密钥”Keys选项卡中添加一个新的对称密钥HMAC将爆破得到的密钥填入。然后你就可以在编辑JWT时选择使用这个密钥对新篡改的Payload进行签名生成一个服务器完全认可的有效令牌。手动使用Hashcat爆破备用方案如果不用插件也可以将JWT和字典导出用Hashcat命令行工具爆破命令格式如下hashcat -m 16500 JWT wordlist-m 16500是Hashcat中JWT的破解模式。这种方式适合批量或分布式爆破但不如在BurpSuite中集成来得方便。注意事项爆破的成功率高度依赖字典质量。对于自定义程度高的系统结合信息收集从JS文件、注释、Git仓库中寻找可能的密钥线索来定制字典至关重要。此外要注意爆破可能触发服务器的速率限制或告警。3.3 攻击手法三算法混淆攻击Algorithm Confusion这是JWT攻击中非常经典且危险的一种手法利用了服务器在验证算法时可能存在的逻辑错误。攻击原理JWT的Header中的alg字段指明了签名算法。常见的算法有对称算法如HS256使用同一个密钥进行签名和验证。非对称算法如RS256使用私钥Private Key签名使用公钥Public Key验证。公钥通常可以公开获取。算法混淆攻击的核心在于诱使服务器使用非对称算法的公钥作为对称算法的密钥来验证我们使用该公钥进行HS256签名的令牌。攻击前提服务器通常使用RS256非对称。服务器错误地将其RS256的公钥同时用于处理alg字段为HS256的令牌验证。即当它看到alg: HS256时它没有使用一个独立的HS256密钥而是错误地使用了RS256的公钥作为HS256的密钥来验证签名。BurpSuite实战步骤获取服务器的公钥这是关键一步。公钥有时会暴露在应用的/jwks.json端点、登录页面的JS文件、甚至网页源码的注释中。在PortSwigger靶场中通常会明确给出或可以通过接口获取。修改Header将JWT的Header中的alg从RS256改为HS256。篡改Payload修改Payload中的用户身份等信息。使用公钥进行HS256签名在JWT Editor插件的“密钥”选项卡中添加一个新的对称密钥HMAC。将获取到的公钥内容通常是PEM格式作为密钥值填入。然后在编辑JWT时选择使用这个“密钥”和HS256算法对篡改后的令牌进行签名。发送请求将新生成的令牌发送给服务器。如果服务器存在混淆漏洞它会用公钥作为HS256的密钥来验证签名而签名正是用这个公钥生成的因此验证通过攻击成功。核心技巧如何判断目标是否存在算法混淆漏洞一个简单的探测方法是将一个有效令牌的alg改为none见下一种攻击如果被拒绝再尝试改为HS256并用你能猜到的或找到的任何可能字符串如“secret”、空字符串、甚至公钥本身作为密钥去签名测试。PortSwigger的靶场会引导你找到公钥但在真实测试中发现公钥需要敏锐的观察力。3.4 攻击手法四alg: none攻击这是一种历史悠久的攻击手法源于JWT规范早期对“无签名”算法的支持。虽然现在的库大多已修复但错误配置或老旧系统仍可能中招。攻击原理JWT规范最初允许alg字段的值为none表示该令牌不进行签名验证。如果服务器配置不当当其接收到一个alg为none的JWT时可能会直接跳过签名验证步骤信任Payload中的数据。BurpSuite实战步骤修改Header将原始JWT的Header中的alg值如HS256改为none。移除签名将整个JWT的第三部分Signature完全删除。此时令牌格式应为xxxxx.yyyyy.末尾有一个点或者更常见的是直接去掉点和第三部分变成xxxxx.yyyyy。篡改Payload同样修改Payload中的用户信息。发送请求有些服务器实现要求即使alg为none第三部分也必须为空所以发送xxxxx.yyyyy.点号保留有些则直接接受xxxxx.yyyyy。需要测试两种情况。重要提示现代标准的JWT库如java-jwt,pyjwt,auth0/node-jsonwebtoken等默认会拒绝alg: none的令牌。因此这种攻击在2023年后的新系统上直接成功的概率较低。但它仍然是一个重要的测试步骤因为它能帮你快速判断服务器验证逻辑的严格程度。如果none攻击成功说明服务器的JWT验证存在严重缺陷。3.5 攻击手法五密钥泄露与JKU/JWK参数注入这种攻击手法更高级针对的是JWT扩展参数。JWT标准允许通过Header中的jkuJWK Set URL或jwJSON Web Key参数来指定验证密钥的来源。如果服务器信任这些参数且攻击者能控制其指向的内容就可以实施攻击。攻击原理jku一个URL指向一个包含公钥集的JSON文件JWK Set。服务器会从这个URL获取公钥来验证签名。jw直接在JWT Header中嵌入一个JSON Web Key公钥。攻击场景是服务器原本使用固定的密钥验证JWT但其代码逻辑是如果检测到Header里有jku或jw参数就优先使用这些参数指定的密钥进行验证。攻击者可以伪造一个JWT将其alg改为RS256。在Header中加入jku参数指向一个由攻击者控制的服务器如BurpSuite的Collaborator客户端或一个公开的存储服务该服务器托管着一个包含攻击者自己生成的RSA公钥的JWK Set文件。使用攻击者自己持有的、与上述公钥对应的私钥对这个JWT进行签名。服务器在验证时会去访问jku指向的URL获取攻击者放置的公钥并用它来验证签名。由于签名确实是用对应的私钥生成的验证通过攻击者成功注入了一个完全受控的密钥。BurpSuite实战步骤以jku注入为例准备恶意JWK Set使用JWT Editor插件在“密钥”选项卡中生成一对新的RSA密钥。然后在插件中可以将公钥导出为JWK格式。你需要将这个JWK格式的公钥放置在一个JSON数组中格式如下并托管到一个你能控制的URL上{ keys: [ { /* 你的RSA公钥JWK内容 */ } ] }构造恶意JWT拦截一个正常请求在Repeater中通过JWT Editor修改其Header。首先将alg改为RS256。然后在Header中添加jku字段值为你托管的恶意JWK Set文件的URL。篡改与签名修改Payload中的数据。然后在JWT Editor的签名选项中选择使用你刚刚生成的RSA私钥与jku中公钥对应进行签名。发送请求发送这个精心构造的JWT。如果服务器存在jku信任漏洞它会从你的URL获取公钥并验证成功。实操心得这种攻击成功的关键在于服务器是否对jku或jw参数进行严格的过滤。安全的实现应该只信任预置的、固定的JWK Set URL或者对传入的URL进行白名单校验。在测试时可以尝试将jku指向一个已知的、合法的服务如https://portswigger.net/观察服务器行为或者使用BurpSuite的Collaborator来探测服务器是否会对外发起请求这本身就是一种安全风险。4. PortSwigger靶场通关流程与技巧实录了解了所有攻击手法后我们以PortSwigger靶场的几个典型实验为例串联起完整的攻击流程。靶场实验是循序渐进的建议按顺序完成。4.1 实验一通过未验证签名的JWT绕过认证目标修改你账户的JWT以其他用户carlos身份访问管理面板并删除其账户。通关流程使用提供的凭据wiener:peter登录靶场。用BurpSuite拦截登录后任意请求如访问/my-account发现Cookie中包含JWT。发送该请求到Repeater使用JWT Editor插件查看Payload发现包含sub字段值为wiener。将sub的值修改为administrator根据实验描述管理员用户名为administrator。关键点由于此关是“未验证签名”我们无需关心签名。在JWT Editor中修改后直接发送请求。观察响应成功跳转到管理员面板。在管理员面板中找到删除carlos用户的API接口用同样的方法使用篡改后的JWT发送删除请求完成实验。技巧如果直接修改sub不成功可以尝试查看Payload中是否有其他标识权限的字段如role、admin、isAdmin等。PortSwigger的靶场设计得很清晰通常关键字段名一目了然。4.2 实验二通过弱密钥爆破JWT密钥目标爆破JWT的密钥并利用它伪造一个以administrator身份登录的令牌。通关流程登录后拦截请求获取有效JWT。在JWT Editor插件的“攻击”选项卡中选择“对称密钥爆破”。准备字典这是核心。实验描述或页面源码中可能会给出密钥的提示例如在页脚注释里。如果没有需要使用一个较大的通用密钥字典。PortSwigger实验的密钥通常不会太复杂但也在常见弱口令字典中。将JWT粘贴到爆破窗口加载你的字典文件开始爆破。爆破成功后插件会显示密钥例如secret1。在“密钥”选项卡中添加这个密钥作为一个新的HMAC密钥。回到Repeater编辑JWT将sub改为administrator然后在签名选项中选择你刚刚添加的密钥算法为HS256生成新令牌。替换原请求中的Cookie发送即可获得管理员权限。避坑指南如果爆破时间过长或无结果首先检查JWT是否确实是HS256算法查看Header。其次尝试一个更小、更精准的字典。有时密钥可能是一个简单的数字或单词的拼接。4.3 实验三通过算法混淆攻击绕过JWT验证目标利用算法混淆漏洞使用提供的公钥伪造一个以administrator身份登录的令牌。通关流程登录后在页面或请求响应中寻找公钥。实验通常会通过一个/jwks.json或类似的接口暴露公钥。用浏览器访问或BurpSuite拦截获取这个公钥PEM格式。在JWT Editor的“密钥”选项卡中点击“New Symmetric Key”。在生成界面点击“Generate”生成一个但不要用它。我们需要的是将获取到的公钥作为密钥。更简单的方法是在“密钥”列表右键“Copy Public Key as JWK”然后“New Symmetric Key”时选择“JWK”粘贴进去。但注意这里需要将kty密钥类型从RSA改为oct并确保公钥内容在k字段中Base64编码格式。这个过程有些繁琐JWT Editor插件的新版本可能简化了操作核心思想是把公钥材料当作一个对称密钥的密钥值。拦截一个普通请求在Repeater中修改JWT。首先将Header中的alg改为HS256。修改Payload中的sub为administrator。在JWT Editor的签名选项中选择你刚才创建的、包含服务器公钥的那个对称密钥进行签名。发送请求。服务器会用它的公钥当作HS256的密钥来验证你的签名由于你的签名正是用这个“密钥”生成的验证通过。核心难点这一步的难点在于正确地将RSA公钥格式转换为JWT Editor可用的对称密钥格式。你需要理解JWK的结构。一个可行的替代方法是使用命令行工具jwt-tool它有一个专门的-X k选项用于算法混淆攻击能自动处理公钥转换。4.4 实验四综合挑战PortSwigger的高级实验往往是以上多种手法的结合。例如可能需要你先爆破一个弱密钥发现它是某个用户的密钥然后用它签名一个令牌但发现权限不够。接着你可能需要分析其他接口发现服务器信任jku参数然后构造一个jku注入攻击最终提升到最高权限。通用解题思路信息收集仔细阅读实验描述访问所有链接查看页面源码、JS文件、HTTP响应头寻找可能的密钥、公钥、API端点线索。测试验证逻辑先用alg: none攻击和简单的Payload篡改不修改签名测试快速判断服务器验证的严格性。分析令牌使用JWT Editor仔细查看Payload的所有字段不光是sub还有iss,aud,nbf,iat,exp以及任何自定义字段。有时漏洞在于其他字段比如kid密钥ID参数注入。工具联动善用BurpSuite的各个模块。用Scanner扫描可能的信息泄露点用Intruder对kid等参数进行模糊测试用Collaborator探测jku等外联请求。循序渐进不要想一步到位。先实现低权限的越权再思考如何组合利用获取更高权限。PortSwigger的实验设计通常是环环相扣的。5. 防御策略与安全开发建议作为攻击者我们研究这些手法是为了更好地防御。如果你是开发者以下是你必须要在代码中落实的检查清单永远验证签名使用经过安全审计的、成熟的JWT库如auth0/node-jsonwebtoken,pyjwt,java-jwt并确保签名验证是强制开启且无法跳过的。指定并固定算法在验证JWT时不要依赖令牌Header中的alg字段。应该在代码中显式指定期望的算法如RS256。例如在pyjwt.decode()中使用algorithms[“RS256”]参数这样即使令牌被改为HS256或none也会被拒绝。使用强密钥并安全存储对于HS256密钥必须是足够长且随机的密码学安全字符串。对于RS256私钥必须严格保密公钥可以公开。密钥决不能硬编码在客户端代码或配置文件中。校验所有声明不仅验证签名还要验证Payload中的声明是否有效且符合预期。iss签发者是否来自可信的颁发者aud受众是否指向本应用exp过期时间令牌是否已过期nbf生效时间令牌是否已生效自定义声明如role,userid是否在预期的范围内禁用有风险的特性明确拒绝alg: none的令牌。如果不需要jku或jw功能应在库层面或应用层面禁用对这些参数的解析和处理。对kid,jku,jw等Header参数进行严格过滤如果必须使用应建立白名单机制只信任预设的、内部的URL或密钥ID绝不信任用户可控的输入。定期轮换密钥制定密钥轮换策略特别是在怀疑密钥可能泄露时。6. 进阶思考与工具链延伸掌握了以上5种基础手法你已经能够应对绝大多数JWT相关的漏洞挑战。但在更复杂的真实环境或CTF比赛中还有一些进阶场景kidKey ID参数注入类似于jkukid是Header中的一个参数用于指示使用哪个密钥。如果服务器根据kid从数据库或文件系统中动态加载密钥并且kid值用户可控如kid: “../../../../path/to/file”就可能造成路径遍历让服务器使用一个攻击者已知的文件如/dev/null或Web目录下的静态文件作为密钥来验证签名。时间攻击Timing Attacks在验证签名时如果字符串比较使用的是普通的不安全比较如攻击者可能通过精确测量响应时间的微小差异逐步推测出签名内容。现代库都使用常数时间比较函数来防御此攻击。工具链除了BurpSuitejwt-tool是一个功能强大的命令行JWT测试框架它集成了编码、解码、爆破、混淆、篡改等多种攻击模式可以作为BurpSuite的有力补充。在自动化测试中可以将它集成到你的工作流中。我个人在渗透测试项目中会遵循一个固定的JWT测试流程先简单篡改和none攻击快速摸底然后检查是否有密钥泄露线索并尝试爆破接着测试算法混淆最后再深入检查kid、jku等高级参数。这套组合拳下来JWT这层的安全隐患基本无处遁形。记住安全是一个持续的过程理解攻击是为了构建更坚固的防御。希望这篇超详细的解析能成为你Web安全武器库中一件称手的利器。
JWT攻击实战:5种手法与BurpSuite靶场通关指南
1. 项目概述为什么JWT攻击是Web安全测试的必修课如果你是一名Web安全测试人员或渗透测试爱好者那么“JWT攻击”这个词你一定不陌生。它就像一把双刃剑一方面JSON Web TokenJWT因其无状态、自包含的特性成为现代Web应用身份认证的主流方案另一方面如果开发者对其实现不当它又会成为攻击者绕过认证、垂直越权甚至接管账户的绝佳跳板。我见过太多项目前端界面做得光鲜亮丽后端逻辑也足够复杂但偏偏在JWT这个看似简单的“令牌”上栽了跟头导致整个认证体系形同虚设。这次我们不谈枯燥的理论直接上手实战。我将结合BurpSuite这款渗透测试“瑞士军刀”以及PortSwiggerBurpSuite官方出品的权威靶场为你完整拆解5种最常见、也最致命的JWT攻击手法。这不仅仅是“通关指南”更是一份从攻击者视角理解JWT安全缺陷的“内功心法”。无论你是想系统学习Web安全还是准备面试中的安全测试环节或是想加固自己开发的应用这里的内容都能让你获得立竿见影的提升。我们会从最基础的JWT结构讲起一步步深入到如何利用BurpSuite的JWT Editor插件篡改令牌、如何暴力破解弱密钥、如何利用算法混淆绕过验证最终实现权限提升。整个过程我会穿插大量我在实际测试和CTF比赛中踩过的坑和总结的技巧确保你不仅能“复现”更能“理解”和“举一反三”。2. 核心攻击手法原理与前置知识拆解在动手之前我们必须把“武器”和“靶子”都搞清楚。JWT攻击的核心在于理解其“自包含”和“可解码”的特性与服务器端验证逻辑之间的“信任间隙”。而BurpSuite和PortSwigger靶场则是我们演练这些攻击最理想的“训练场”。2.1 JWT结构三要素Header, Payload, Signature一个标准的JWT看起来像这样xxxxx.yyyyy.zzzzz由点号分隔的三部分组成。很多新手会直接把它当作一个加密的、不可读的字符串这是第一个误区。实际上JWT的前两部分Header和Payload仅仅是Base64Url编码的JSON对象任何人都可以轻松解码查看。Header头部通常包含令牌类型typ: “JWT”和所使用的签名算法alg如HS256HMAC SHA-256或RS256RSA SHA-256。这个alg字段是后续多种攻击手法的关键切入点。Payload负载包含了所谓的“声明”Claims也就是实际要传递的信息。常见声明有iss签发者、sub主题用户、exp过期时间、以及自定义的业务字段如username、admin、user_id等。攻击者的核心目标就是篡改这部分数据例如将username: “guest”改为username: “admin”。Signature签名这是JWT安全性的基石。服务器使用Header中指定的算法和一个密钥Secret Key或私钥对“Base64Url编码的Header” “.” “Base64Url编码的Payload”进行签名。签名的目的是验证消息在传输过程中未被篡改。服务器验证JWT的典型流程是收到令牌后用同样的密钥和算法重新计算签名并与令牌中的第三部分Signature进行比对。如果一致则认为令牌有效且未被篡改然后信任Payload中的数据。整个攻击逻辑都围绕“如何让服务器接受一个被我们篡改过Payload但签名验证仍能通过或绕过的JWT”而展开。2.2 攻击环境搭建BurpSuite与JWT Editor插件工欲善其事必先利其器。BurpSuite Professional是本次实战的核心工具社区版功能受限建议使用专业版。除了基本的Proxy代理、Repeater重放模块我们最关键的一个武器是“JWT Editor”插件。注意JWT Editor插件并非BurpSuite自带需要手动安装。你可以在BApp Store中搜索“JWT Editor”进行安装。安装后它会在Burp的多个标签页如Proxy历史、Repeater中增加一个“JSON Web Token”子标签方便你直接解码、编辑和重新签名JWT。为什么这个插件如此重要因为它将手动处理JWT的繁琐过程Base64编解码、JSON格式化、签名计算完全自动化了。在攻击过程中我们经常需要快速修改Payload中的某个字段比如把admin: false改成true然后尝试用不同的密钥或算法重新签名。没有这个插件你需要频繁切换解码网站和命令行工具效率极低且容易出错。有了它你可以在BurpSuite的界面内一键完成所有操作攻击流程变得行云流水。2.3 PortSwigger靶场理想的实战沙盒PortSwigger Web Security Academy网络安全学院的靶场是学习Web安全的黄金标准。它的JWT实验场景设计得非常精妙每一关都对应一种典型的JWT安全漏洞场景并且提供了真实的、有漏洞的Web应用环境。与DVWA、Pikachu等综合靶场不同PortSwigger的JWT实验目标单一干扰少非常适合专项突破。在开始前请确保你已经配置好BurpSuite并将浏览器代理指向Burp通常是127.0.0.1:8080。已安装并正确加载JWT Editor插件。访问PortSwigger官网找到“JWT attacks”模块下的实验Lab从第一个开始。每个实验都有明确的目标例如“绕过认证访问管理面板”或“以其他用户身份发布文章”。3. 5种核心JWT攻击手法实战解析下面我们进入正题逐一拆解这5种攻击手法。我会以PortSwigger靶场为背景详细说明攻击步骤、BurpSuite操作要点以及背后的原理。3.1 攻击手法一未验证签名——直接篡改Payload这是最基础但也最容易被忽视的一种漏洞。当服务器在验证JWT时根本没有检查签名部分或者验证逻辑存在缺陷例如只解码了Payload并使用了其中的数据但跳过了签名验证步骤。在这种情况下JWT的“签名”形同虚设。攻击原理由于Header和Payload只是Base64Url编码我们可以直接解码修改Payload中的关键信息如用户ID、角色权限然后重新编码拼接成一个新的、没有有效签名的令牌发送给服务器。服务器因为不验证签名会直接信任我们篡改后的数据。BurpSuite实战步骤拦截请求使用BurpSuite Proxy拦截一个包含JWT的HTTP请求通常在Authorization: Bearer JWT头或Cookie中。发送至Repeater右键点击请求发送到Repeater模块以便反复测试。解码与分析在Repeater中找到JWT所在的位置。如果安装了JWT Editor插件请求内容旁边会自动出现“JSON Web Token”标签页点击即可直观地看到解码后的Header和Payload。如果没有插件你可以复制xxxxx.yyyyy这部分到BurpSuite的Decoder模块进行Base64Url解码。篡改Payload在Payload部分找到标识用户身份或权限的字段。例如将sub: wiener普通用户修改为sub: administrator或carlos目标用户。或者将role: user修改为role: admin。重新编码与发送使用JWT Editor插件修改后它会自动更新整个JWT字符串。如果没有插件你需要手动将修改后的JSON进行Base64Url编码替换掉原来的yyyyy部分并保持第三部分签名zzzzz不变或直接删除如果服务器不检查。然后将这个篡改后的令牌放回原请求位置点击“Send”发送。观察响应如果服务器返回了成功访问目标资源如管理页面的响应则攻击成功。实操心得这种漏洞在实际中比想象中要多尤其是在一些快速开发、对安全不够重视的内部系统或早期版本中。测试时一个快速验证的方法就是直接删除JWT的第三部分签名只发送xxxxx.yyyyy.注意最后有个点看服务器是否依然接受。如果接受那问题就严重了。3.2 攻击手法二弱密钥爆破Brute-Force当JWT使用对称加密算法如HS256时服务器和客户端共享同一个密钥Secret来签名和验证。如果这个密钥强度不够例如是常见的单词、短字符串、或与项目名相关攻击者就有可能通过暴力破解的方式猜出密钥。攻击原理HS256签名本质上是一个带密钥的哈希HMAC。如果我们有了一段有效的JWT包含Header、Payload和Signature我们就可以尝试用一份常见的密钥字典如secret,password,123456, 项目名称等对已知的Header和Payload重新计算签名如果计算出的签名与原始JWT中的Signature一致那么就找到了正确的密钥。一旦获得密钥我们就可以为任意Payload生成合法的签名完全控制令牌。BurpSuite实战步骤结合Intruder模块获取样本令牌同样先拦截一个有效的JWT请求。使用JWT Editor插件爆破这是最高效的方法。在JWT Editor插件的“攻击”Attack选项卡中选择“对称密钥爆破”Brute-force secret。配置爆破参数将拦截到的JWT粘贴进去。你需要准备一个高质量的密钥字典。可以自己根据目标信息生成如公司名、项目名、常见弱口令也可以使用SecLists项目中的JWT-secrets.txt等专用字典。执行与识别点击开始插件会自动用字典中的每个密钥尝试对已知的Header和Payload进行签名并与原签名比对。爆破成功后插件会直接显示正确的密钥。利用密钥在JWT Editor的“密钥”Keys选项卡中添加一个新的对称密钥HMAC将爆破得到的密钥填入。然后你就可以在编辑JWT时选择使用这个密钥对新篡改的Payload进行签名生成一个服务器完全认可的有效令牌。手动使用Hashcat爆破备用方案如果不用插件也可以将JWT和字典导出用Hashcat命令行工具爆破命令格式如下hashcat -m 16500 JWT wordlist-m 16500是Hashcat中JWT的破解模式。这种方式适合批量或分布式爆破但不如在BurpSuite中集成来得方便。注意事项爆破的成功率高度依赖字典质量。对于自定义程度高的系统结合信息收集从JS文件、注释、Git仓库中寻找可能的密钥线索来定制字典至关重要。此外要注意爆破可能触发服务器的速率限制或告警。3.3 攻击手法三算法混淆攻击Algorithm Confusion这是JWT攻击中非常经典且危险的一种手法利用了服务器在验证算法时可能存在的逻辑错误。攻击原理JWT的Header中的alg字段指明了签名算法。常见的算法有对称算法如HS256使用同一个密钥进行签名和验证。非对称算法如RS256使用私钥Private Key签名使用公钥Public Key验证。公钥通常可以公开获取。算法混淆攻击的核心在于诱使服务器使用非对称算法的公钥作为对称算法的密钥来验证我们使用该公钥进行HS256签名的令牌。攻击前提服务器通常使用RS256非对称。服务器错误地将其RS256的公钥同时用于处理alg字段为HS256的令牌验证。即当它看到alg: HS256时它没有使用一个独立的HS256密钥而是错误地使用了RS256的公钥作为HS256的密钥来验证签名。BurpSuite实战步骤获取服务器的公钥这是关键一步。公钥有时会暴露在应用的/jwks.json端点、登录页面的JS文件、甚至网页源码的注释中。在PortSwigger靶场中通常会明确给出或可以通过接口获取。修改Header将JWT的Header中的alg从RS256改为HS256。篡改Payload修改Payload中的用户身份等信息。使用公钥进行HS256签名在JWT Editor插件的“密钥”选项卡中添加一个新的对称密钥HMAC。将获取到的公钥内容通常是PEM格式作为密钥值填入。然后在编辑JWT时选择使用这个“密钥”和HS256算法对篡改后的令牌进行签名。发送请求将新生成的令牌发送给服务器。如果服务器存在混淆漏洞它会用公钥作为HS256的密钥来验证签名而签名正是用这个公钥生成的因此验证通过攻击成功。核心技巧如何判断目标是否存在算法混淆漏洞一个简单的探测方法是将一个有效令牌的alg改为none见下一种攻击如果被拒绝再尝试改为HS256并用你能猜到的或找到的任何可能字符串如“secret”、空字符串、甚至公钥本身作为密钥去签名测试。PortSwigger的靶场会引导你找到公钥但在真实测试中发现公钥需要敏锐的观察力。3.4 攻击手法四alg: none攻击这是一种历史悠久的攻击手法源于JWT规范早期对“无签名”算法的支持。虽然现在的库大多已修复但错误配置或老旧系统仍可能中招。攻击原理JWT规范最初允许alg字段的值为none表示该令牌不进行签名验证。如果服务器配置不当当其接收到一个alg为none的JWT时可能会直接跳过签名验证步骤信任Payload中的数据。BurpSuite实战步骤修改Header将原始JWT的Header中的alg值如HS256改为none。移除签名将整个JWT的第三部分Signature完全删除。此时令牌格式应为xxxxx.yyyyy.末尾有一个点或者更常见的是直接去掉点和第三部分变成xxxxx.yyyyy。篡改Payload同样修改Payload中的用户信息。发送请求有些服务器实现要求即使alg为none第三部分也必须为空所以发送xxxxx.yyyyy.点号保留有些则直接接受xxxxx.yyyyy。需要测试两种情况。重要提示现代标准的JWT库如java-jwt,pyjwt,auth0/node-jsonwebtoken等默认会拒绝alg: none的令牌。因此这种攻击在2023年后的新系统上直接成功的概率较低。但它仍然是一个重要的测试步骤因为它能帮你快速判断服务器验证逻辑的严格程度。如果none攻击成功说明服务器的JWT验证存在严重缺陷。3.5 攻击手法五密钥泄露与JKU/JWK参数注入这种攻击手法更高级针对的是JWT扩展参数。JWT标准允许通过Header中的jkuJWK Set URL或jwJSON Web Key参数来指定验证密钥的来源。如果服务器信任这些参数且攻击者能控制其指向的内容就可以实施攻击。攻击原理jku一个URL指向一个包含公钥集的JSON文件JWK Set。服务器会从这个URL获取公钥来验证签名。jw直接在JWT Header中嵌入一个JSON Web Key公钥。攻击场景是服务器原本使用固定的密钥验证JWT但其代码逻辑是如果检测到Header里有jku或jw参数就优先使用这些参数指定的密钥进行验证。攻击者可以伪造一个JWT将其alg改为RS256。在Header中加入jku参数指向一个由攻击者控制的服务器如BurpSuite的Collaborator客户端或一个公开的存储服务该服务器托管着一个包含攻击者自己生成的RSA公钥的JWK Set文件。使用攻击者自己持有的、与上述公钥对应的私钥对这个JWT进行签名。服务器在验证时会去访问jku指向的URL获取攻击者放置的公钥并用它来验证签名。由于签名确实是用对应的私钥生成的验证通过攻击者成功注入了一个完全受控的密钥。BurpSuite实战步骤以jku注入为例准备恶意JWK Set使用JWT Editor插件在“密钥”选项卡中生成一对新的RSA密钥。然后在插件中可以将公钥导出为JWK格式。你需要将这个JWK格式的公钥放置在一个JSON数组中格式如下并托管到一个你能控制的URL上{ keys: [ { /* 你的RSA公钥JWK内容 */ } ] }构造恶意JWT拦截一个正常请求在Repeater中通过JWT Editor修改其Header。首先将alg改为RS256。然后在Header中添加jku字段值为你托管的恶意JWK Set文件的URL。篡改与签名修改Payload中的数据。然后在JWT Editor的签名选项中选择使用你刚刚生成的RSA私钥与jku中公钥对应进行签名。发送请求发送这个精心构造的JWT。如果服务器存在jku信任漏洞它会从你的URL获取公钥并验证成功。实操心得这种攻击成功的关键在于服务器是否对jku或jw参数进行严格的过滤。安全的实现应该只信任预置的、固定的JWK Set URL或者对传入的URL进行白名单校验。在测试时可以尝试将jku指向一个已知的、合法的服务如https://portswigger.net/观察服务器行为或者使用BurpSuite的Collaborator来探测服务器是否会对外发起请求这本身就是一种安全风险。4. PortSwigger靶场通关流程与技巧实录了解了所有攻击手法后我们以PortSwigger靶场的几个典型实验为例串联起完整的攻击流程。靶场实验是循序渐进的建议按顺序完成。4.1 实验一通过未验证签名的JWT绕过认证目标修改你账户的JWT以其他用户carlos身份访问管理面板并删除其账户。通关流程使用提供的凭据wiener:peter登录靶场。用BurpSuite拦截登录后任意请求如访问/my-account发现Cookie中包含JWT。发送该请求到Repeater使用JWT Editor插件查看Payload发现包含sub字段值为wiener。将sub的值修改为administrator根据实验描述管理员用户名为administrator。关键点由于此关是“未验证签名”我们无需关心签名。在JWT Editor中修改后直接发送请求。观察响应成功跳转到管理员面板。在管理员面板中找到删除carlos用户的API接口用同样的方法使用篡改后的JWT发送删除请求完成实验。技巧如果直接修改sub不成功可以尝试查看Payload中是否有其他标识权限的字段如role、admin、isAdmin等。PortSwigger的靶场设计得很清晰通常关键字段名一目了然。4.2 实验二通过弱密钥爆破JWT密钥目标爆破JWT的密钥并利用它伪造一个以administrator身份登录的令牌。通关流程登录后拦截请求获取有效JWT。在JWT Editor插件的“攻击”选项卡中选择“对称密钥爆破”。准备字典这是核心。实验描述或页面源码中可能会给出密钥的提示例如在页脚注释里。如果没有需要使用一个较大的通用密钥字典。PortSwigger实验的密钥通常不会太复杂但也在常见弱口令字典中。将JWT粘贴到爆破窗口加载你的字典文件开始爆破。爆破成功后插件会显示密钥例如secret1。在“密钥”选项卡中添加这个密钥作为一个新的HMAC密钥。回到Repeater编辑JWT将sub改为administrator然后在签名选项中选择你刚刚添加的密钥算法为HS256生成新令牌。替换原请求中的Cookie发送即可获得管理员权限。避坑指南如果爆破时间过长或无结果首先检查JWT是否确实是HS256算法查看Header。其次尝试一个更小、更精准的字典。有时密钥可能是一个简单的数字或单词的拼接。4.3 实验三通过算法混淆攻击绕过JWT验证目标利用算法混淆漏洞使用提供的公钥伪造一个以administrator身份登录的令牌。通关流程登录后在页面或请求响应中寻找公钥。实验通常会通过一个/jwks.json或类似的接口暴露公钥。用浏览器访问或BurpSuite拦截获取这个公钥PEM格式。在JWT Editor的“密钥”选项卡中点击“New Symmetric Key”。在生成界面点击“Generate”生成一个但不要用它。我们需要的是将获取到的公钥作为密钥。更简单的方法是在“密钥”列表右键“Copy Public Key as JWK”然后“New Symmetric Key”时选择“JWK”粘贴进去。但注意这里需要将kty密钥类型从RSA改为oct并确保公钥内容在k字段中Base64编码格式。这个过程有些繁琐JWT Editor插件的新版本可能简化了操作核心思想是把公钥材料当作一个对称密钥的密钥值。拦截一个普通请求在Repeater中修改JWT。首先将Header中的alg改为HS256。修改Payload中的sub为administrator。在JWT Editor的签名选项中选择你刚才创建的、包含服务器公钥的那个对称密钥进行签名。发送请求。服务器会用它的公钥当作HS256的密钥来验证你的签名由于你的签名正是用这个“密钥”生成的验证通过。核心难点这一步的难点在于正确地将RSA公钥格式转换为JWT Editor可用的对称密钥格式。你需要理解JWK的结构。一个可行的替代方法是使用命令行工具jwt-tool它有一个专门的-X k选项用于算法混淆攻击能自动处理公钥转换。4.4 实验四综合挑战PortSwigger的高级实验往往是以上多种手法的结合。例如可能需要你先爆破一个弱密钥发现它是某个用户的密钥然后用它签名一个令牌但发现权限不够。接着你可能需要分析其他接口发现服务器信任jku参数然后构造一个jku注入攻击最终提升到最高权限。通用解题思路信息收集仔细阅读实验描述访问所有链接查看页面源码、JS文件、HTTP响应头寻找可能的密钥、公钥、API端点线索。测试验证逻辑先用alg: none攻击和简单的Payload篡改不修改签名测试快速判断服务器验证的严格性。分析令牌使用JWT Editor仔细查看Payload的所有字段不光是sub还有iss,aud,nbf,iat,exp以及任何自定义字段。有时漏洞在于其他字段比如kid密钥ID参数注入。工具联动善用BurpSuite的各个模块。用Scanner扫描可能的信息泄露点用Intruder对kid等参数进行模糊测试用Collaborator探测jku等外联请求。循序渐进不要想一步到位。先实现低权限的越权再思考如何组合利用获取更高权限。PortSwigger的实验设计通常是环环相扣的。5. 防御策略与安全开发建议作为攻击者我们研究这些手法是为了更好地防御。如果你是开发者以下是你必须要在代码中落实的检查清单永远验证签名使用经过安全审计的、成熟的JWT库如auth0/node-jsonwebtoken,pyjwt,java-jwt并确保签名验证是强制开启且无法跳过的。指定并固定算法在验证JWT时不要依赖令牌Header中的alg字段。应该在代码中显式指定期望的算法如RS256。例如在pyjwt.decode()中使用algorithms[“RS256”]参数这样即使令牌被改为HS256或none也会被拒绝。使用强密钥并安全存储对于HS256密钥必须是足够长且随机的密码学安全字符串。对于RS256私钥必须严格保密公钥可以公开。密钥决不能硬编码在客户端代码或配置文件中。校验所有声明不仅验证签名还要验证Payload中的声明是否有效且符合预期。iss签发者是否来自可信的颁发者aud受众是否指向本应用exp过期时间令牌是否已过期nbf生效时间令牌是否已生效自定义声明如role,userid是否在预期的范围内禁用有风险的特性明确拒绝alg: none的令牌。如果不需要jku或jw功能应在库层面或应用层面禁用对这些参数的解析和处理。对kid,jku,jw等Header参数进行严格过滤如果必须使用应建立白名单机制只信任预设的、内部的URL或密钥ID绝不信任用户可控的输入。定期轮换密钥制定密钥轮换策略特别是在怀疑密钥可能泄露时。6. 进阶思考与工具链延伸掌握了以上5种基础手法你已经能够应对绝大多数JWT相关的漏洞挑战。但在更复杂的真实环境或CTF比赛中还有一些进阶场景kidKey ID参数注入类似于jkukid是Header中的一个参数用于指示使用哪个密钥。如果服务器根据kid从数据库或文件系统中动态加载密钥并且kid值用户可控如kid: “../../../../path/to/file”就可能造成路径遍历让服务器使用一个攻击者已知的文件如/dev/null或Web目录下的静态文件作为密钥来验证签名。时间攻击Timing Attacks在验证签名时如果字符串比较使用的是普通的不安全比较如攻击者可能通过精确测量响应时间的微小差异逐步推测出签名内容。现代库都使用常数时间比较函数来防御此攻击。工具链除了BurpSuitejwt-tool是一个功能强大的命令行JWT测试框架它集成了编码、解码、爆破、混淆、篡改等多种攻击模式可以作为BurpSuite的有力补充。在自动化测试中可以将它集成到你的工作流中。我个人在渗透测试项目中会遵循一个固定的JWT测试流程先简单篡改和none攻击快速摸底然后检查是否有密钥泄露线索并尝试爆破接着测试算法混淆最后再深入检查kid、jku等高级参数。这套组合拳下来JWT这层的安全隐患基本无处遁形。记住安全是一个持续的过程理解攻击是为了构建更坚固的防御。希望这篇超详细的解析能成为你Web安全武器库中一件称手的利器。