【Academy】JWT 分析 ------ JWT
JWT 分析 ------ JWT
- 1. 什么是 JWT?
- 1.1 JWT 格式
- 1.2 JWT 签名
- 1.3 JWT 与 JWS 与 JWE
- 2. 什么是 JWT 漏洞?
- 3. JWT 漏洞的影响是什么?
- 4. JWT 的漏洞是如何产生的?
- 5. 如何在 Burp Suite 中使用 JWT
- 6. 利用有缺陷的 JWT 签名验证
- 6.1 接受任意签名
- 6.2 接受没有签名的令牌
- 7. 暴力破解密钥
- 7.1 使用 hashcat 暴力破解密钥
- 8. JWT 标头参数注入
- 8.1 通过 jwk 参数注入自签名 JWT
- 8.2 通过 jku 参数注入自签名 JWT
- 8.3 通过 kid 参数注入自签名 JWT
- 8.4 其他有趣的 JWT 标头参数
- 9. JWT 算法混淆
- 9.1 对称与非对称算法
- 9.2 算法混淆漏洞是如何产生的?
- 9.3 执行算法混淆
- 第 1 步 - 获取服务器的公钥
- 第 2 步 - 将公钥转换为合适的格式
- 第 3 步 - 修改 JWT
- 第 4 步 - 使用公钥对 JWT 进行签名
- 9.4 从现有令牌派生公钥
- 10. 如何防止 JWT 攻击
- 10.1 JWT 处理的其他最佳实践
概述
在本节中,我们将探讨设计问题以及对 JSON 网络令牌(JWT)的不当处理如何使网站容易受到各种高严重性攻击。由于 JWT 最常用于身份验证、会话管理和访问控制机制,这些漏洞可能会潜在地危及整个网站及其用户。
1. 什么是 JWT?
JSON Web 令牌 (JWT) 是一种标准化格式,用于在系统之间发送加密签名的 JSON 数据。理论上,它们可以包含任何类型的数据,但最常用于发送有关用户的信息(“声明”),作为身份验证、会话处理和访问控制机制的一部分。
与经典会话令牌不同,服务器所需的所有数据都存储在 JWT 本身的客户端。这使得 JWT 成为高度分布式网站的热门选择,在这些网站中,用户需要与多个后端服务器无缝交互。
1.1 JWT 格式
JWT 由 3 部分组成:标头、有效负载和签名。每个字段都由一个点分隔,如以下示例所示:
eyJraWQiOiI5MTM2ZGRiMy1jYjBhLTRhMTktYTA3ZS1lYWRmNWE0NGM4YjUiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTY0ODAzNzE2NCwibmFtZSI6IkNhcmxvcyBNb250b3lhIiwic3ViIjoiY2FybG9zIiwicm9sZSI6ImJsb2dfYXV0aG9yIiwiZW1haWwiOiJjYXJsb3NAY2FybG9zLW1vbnRveWEubmV0IiwiaWF0IjoxNTE2MjM5MDIyfQ.SYZBPIBg2CRjXAJ8vCER0LA_ENjII1JakvNQoP-Hw6GG1zfl4JyngsZReIfqRvIAEi5L4HV0q7_9qGhQZvy9ZdxEJbwTxRs_6Lb-fZTDpW6lKYNdMyjw45_alSCZ1fypsMWz_2mTpQzil0lOtps5Ei_z7mM7M8gCwe_AGpI53JxduQOaB5HkT5gVrv9cKu9CsW5MS6ZbqYXpGyOG5ehoxqm8DL5tFYaW3lB50ELxi0KsuTKEbD0t5BCl0aCR2MBJWAbN-xeLwEenaqBiwPVvKixYleeDQiBEIylFdNNIMviKRgXiYuAvMziVPbwSgkZVHeEdF5MQP1Oe2Spac-6IfA
JWT 的标头和有效负载部分只是 base64url 编码的 JSON 对象。标头包含有关令牌本身的元数据,而有效负载包含有关用户的实际“声明”。例如,您可以从上面的令牌中解码有效负载,以显示以下声明:
{
"iss": "portswigger",
"exp": 1648037164,
"name": "Carlos Montoya",
"sub": "carlos",
"role": "blog_author",
"email": "carlos@carlos-montoya.net",
"iat": 1516239022
}
在大多数情况下,任何有权访问令牌的人都可以轻松读取或修改此数据。因此,任何基于 JWT 的机制的安全性都严重依赖于加密签名。
1.2 JWT 签名
颁发令牌的服务器通常通过对标头和有效负载进行哈希处理来生成签名。在某些情况下,它们还会加密生成的哈希值。无论哪种方式,此过程都涉及秘密签名密钥。此机制为服务器提供了一种方法来验证令牌中的任何数据自颁发以来是否未被篡改:
-
由于签名是直接从令牌的其余部分派生的,因此更改标头或有效负载的单个字节会导致签名不匹配。
-
如果不知道服务器的秘密签名密钥,就不可能为给定的标头或有效负载生成正确的签名。
Tip
如果你想更好地了解 JWT 是如何构造的,可以使用 jwt.io
上的调试器来试验任意令牌。
1.3 JWT 与 JWS 与 JWE
JWT 规范实际上非常有限。它仅定义一种格式,用于将信息(“声明”)表示为可在两方之间传输的 JSON 对象。在实践中,JWT 并没有真正用作独立实体。JWT 规范由 JSON Web 签名 (JWS) 和 JSON Web 加密 (JWE) 规范进行扩展,它们定义了实际实现 JWT 的具体方法。
换句话说,JWT 通常是 JWS 或 JWE 令牌。当人们使用术语“JWT”时,他们几乎总是指的是 JWS 令牌。JWE 非常相似,只是令牌的实际内容是加密的,而不仅仅是编码的。
注意
为简单起见,在这些材料中,“JWT”主要是指 JWS 令牌,尽管所描述的某些漏洞也可能适用于 JWE 令牌。
2. 什么是 JWT 漏洞?
JWT 漏洞涉及用户向服务器发送修改后的 JWT,以实现恶意目的。通常,这个目的是通过冒充已通过身份验证的其他用户来绕过身份验证和访问控制。
3. JWT 漏洞的影响是什么?
JWT 漏洞的影响通常很严重。如果攻击者能够创建具有任意值的有效令牌,他们可能会提升自己的权限或冒充其他用户,完全控制他们的账户。
4. JWT 的漏洞是如何产生的?
JWT 漏洞通常是由于应用程序本身中的 JWT 处理有缺陷而出现的。与 JWT 相关的各种规范在设计上相对灵活,允许网站开发人员自己决定许多实现细节。这可能会导致他们意外引入漏洞,即使在使用经过实战的库时也是如此。
这些实现缺陷通常意味着 JWT 的签名未得到正确验证。这使攻击者能够篡改通过令牌的有效负载传递给应用程序的值。即使签名经过可靠验证,它是否真的可信在很大程度上也取决于服务器的密钥是否保持机密。如果此密钥以某种方式泄露,或者可以被猜到或暴力破解,攻击者可以为任何任意令牌生成有效签名,从而破坏整个机制。
5. 如何在 Burp Suite 中使用 JWT
如果您过去没有使用过 JWT,建议您在阅读本文之前熟悉 Burp Suite 的相关功能。
可以使用 Burp Inspector 查看和解码 JWT。然后,可以使用 JWT 编辑器扩展来:
- 生成加密签名密钥
- 编辑 JWT
- 使用与编辑后的 JWT 对应的有效签名重新签署令牌
6. 利用有缺陷的 JWT 签名验证
根据设计,服务器通常不存储有关它们颁发的 JWT 的任何信息。相反,每个令牌都是一个完全独立的实体。这有几个优点,但也引入了一个基本问题 - 服务器实际上不知道令牌的原始内容,甚至不知道原始签名是什么。因此,如果服务器没有正确验证签名,则没有什么可以阻止攻击者对令牌的其余部分进行任意更改。
例如,考虑包含以下声明的 JWT:
{
"username": "carlos",
"isAdmin": false
}
如果服务器根据此username
识别会话,则修改其值可能会使攻击者能够模拟其他登录用户。同样,如果 isAdmin
值用于访问控制,则可以为权限提升提供一个简单的向量。
6.1 接受任意签名
JWT 库通常提供一种方法用于验证令牌,另一种方法仅用于解码令牌。例如,Node.js 库jsonwebtoken
有verify()
和decode()
。
有时,开发人员会混淆这两个方法,只将传入的令牌传递给 decode()
方法。这实际上意味着应用程序根本不验证签名。
6.2 接受没有签名的令牌
除其他外,JWT 头部包含一个alg
参数。这告诉服务器使用了哪种算法对令牌进行签名,因此,在验证签名时需要使用哪种算法。
{
"alg": "HS256",
"typ": "JWT"
}
这本质上是有缺陷的,因为服务器别无选择,只能隐式信任来自令牌的用户可控输入,而此时,该输入根本没有经过验证。换句话说,攻击者可以直接影响服务器检查令牌是否可信的方式。
JWT 可以使用一系列不同的算法进行签名,但也可以保持不签名状态。在这种情况下,alg
参数设置为 none
,这表示所谓的“不安全的 JWT”。由于这样做的明显危险,服务器通常会拒绝没有签名的令牌。但是,由于这种筛选依赖于字符串解析,因此您有时可以使用经典的混淆技术(例如混合大小写和意外编码)绕过这些筛选条件。
注意
即使令牌是未签名的,有效负载部分仍必须以尾随点结束。
7. 暴力破解密钥
某些签名算法(如 HS256 (HMAC + SHA-256))使用任意的独立字符串作为密钥。就像密码一样,攻击者不能轻易猜到或暴力破解此密钥,这一点至关重要。否则,他们可能能够创建具有他们喜欢的任何标头和有效负载值的 JWT,然后使用密钥通过有效签名对令牌重新签名。
在实施 JWT 应用程序时,开发人员有时会犯一些错误,例如忘记更改默认密钥或占位符密钥。他们甚至可能会复制和粘贴他们在网上找到的代码片段,然后忘记更改作为示例提供的硬编码密钥。在这种情况下,攻击者使用已知密钥的单词列表暴力破解服务器的密钥可能很简单。
7.1 使用 hashcat 暴力破解密钥
建议使用 hashcat 暴力破解密钥。你可以手动安装 hashcat,但它在 Kali Linux 上也预装好了,可以直接使用。
注意
如果您使用的是 Kali 的预构建 VirtualBox 镜像而不是裸机安装程序版本,则可能没有分配足够的内存来运行 hashcat。
您只需要来自目标服务器的有效签名 JWT 和已知密钥的单词列表。然后,您可以运行以下命令,将 JWT 和 wordlist 作为参数传入:
hashcat -a 0 -m 16500 <jwt> <wordlist>
Hashcat 使用 wordlist 中的每个密钥对 JWT 中的标头和有效负载进行签名,然后将结果签名与服务器的原始签名进行比较。如果任何签名匹配,hashcat 将按以下格式输出已识别的密钥,以及各种其他详细信息:
<jwt>:<identified-secret>
注意
如果您多次运行该命令,则需要包含--show
标志以输出结果。
由于 hashcat 在您的机器上本地运行,并且不依赖于向服务器发送请求,因此此过程非常快,即使在使用大量字典列表时也是如此。
确定密钥后,您可以使用它为所需的任何 JWT 标头和有效负载生成有效签名。有关如何在 Burp Suite 中对修改后的 JWT 重新签名的详细信息,请参阅编辑 JWT。
如果服务器使用极弱的密钥,甚至可以逐个字符暴力破解此密钥,而不是使用单词列表。
8. JWT 标头参数注入
根据 JWS 规范,只有 alg
标头参数是必需的。但是,在实践中,JWT 标头(也称为 JOSE 标头)通常包含其他几个参数。攻击者对以下选项特别感兴趣。
-
jwk
(JSON Web 密钥)- 提供表示密钥的嵌入式 JSON 对象。 -
jku
(JSON Web 密钥集 URL) - 提供一个 URL,服务器可以从该 URL 中获取包含正确密钥的一组密钥。 -
kid
(Key ID) (密钥 ID) - 提供一个 ID,在有多个密钥可供选择的情况下,服务器可以使用该 ID 来识别正确的密钥。根据键的格式,这可能具有匹配的kid
参数。
如您所见,这些用户可控制的参数都告诉收件人服务器在验证签名时使用哪个密钥。在本节中,您将学习如何利用这些来注入使用您自己的任意密钥(而不是服务器密钥)签名的修改后的 JWT。
8.1 通过 jwk 参数注入自签名 JWT
JSON Web 签名 (JWS) 规范描述了一个可选的 jwk
标头参数,服务器可以使用该参数将其公钥以 JWK 格式直接嵌入到令牌本身中。
JWK
JWK(JSON Web 密钥)是一种用于将密钥表示为 JSON 对象的标准化格式。
您可以在以下 JWT 标头中看到一个示例:
{
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"typ": "JWT",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
}
}
公钥和私钥
如果您不熟悉“公钥”和“私钥”这两个术语,我们已将其作为算法混淆攻击材料的一部分进行了介绍。有关更多信息,请参阅对称算法与非对称算法。
理想情况下,服务器应仅使用有限的公钥白名单来验证 JWT 签名。但是,配置错误的服务器有时会使用 jwk 参数中嵌入的任何密钥。
您可以通过使用自己的 RSA 私有密钥对修改后的 JWT 进行签名,然后将匹配的公有密钥嵌入 jwk 标头来利用此行为。
尽管您可以在 Burp 中手动添加或修改 jwk
参数,但 JWT Editor
扩展提供了一个有用的功能来帮助您测试此漏洞:
-
加载扩展后,在 Burp 的主选项卡栏中,转到 JWT 编辑器键选项卡。
-
生成新的 RSA 密钥。
-
将包含 JWT 的请求发送到 Burp Repeater。
-
在消息编辑器中,切换到扩展生成的 JSON Web 令牌选项卡,并根据需要修改令牌的负载。
-
单击 Attack,然后选择 Embedded JWK。出现提示时,选择新生成的 RSA 密钥。
-
发送请求以测试服务器的响应方式。
您也可以通过自己添加 jwk
标头来手动执行此攻击。但是,您可能还需要更新 JWT 的 kid
标头参数以匹配嵌入密钥的 kid
。该扩展的内置攻击会为您处理此步骤。
8.2 通过 jku 参数注入自签名 JWT
某些服务器允许您使用 jku
(JWK Set URL) 标头参数来引用包含密钥的 JWK 集,而不是直接使用 jwk
标头参数嵌入公钥。验证签名时,服务器会从此 URL 获取相关密钥。
JWK 集
JWK 集是一个 JSON 对象,其中包含表示不同键的 JWK 数组。您可以在下面看到一个示例。
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
"n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
},
{
"kty": "RSA",
"e": "AQAB",
"kid": "d8fDFo-fS9-faS14a9-ASf99sa-7c1Ad5abA",
"n": "fc3f-yy1wpYmffgXBxhAUJzHql79gNNQ_cb33HocCuJolwDqmk6GPM4Y_qTVX67WhsN3JvaFYw-dfg6DH-asAScw"
}
]
}
像这样的 JWK 集有时会通过标准端点公开,比如 /.well-known/jwks.json
。
更安全的网站只会从受信任的域获取密钥,但您有时可以利用 URL 解析差异来绕过此类过滤。参考 SSRF 。
8.3 通过 kid 参数注入自签名 JWT
服务器可以使用多个加密密钥对不同类型的数据进行签名,而不仅仅是 JWT。因此,JWT 的标头可能包含 kid
(Key ID) 参数,该参数可帮助服务器在验证签名时识别要使用的密钥。
验证密钥通常存储为 JWK 集。在这种情况下,服务器可能只是查找与令牌具有相同 kid
的 JWK。但是,JWS 规范并未为此 ID 定义具体结构 - 它只是开发人员选择的任意字符串。例如,他们可能会使用 kid
参数来指向数据库中的特定条目,甚至是文件名。
如果此参数也容易受到目录遍历的攻击,则攻击者可能会强制服务器使用其文件系统中的任意文件作为验证密钥。
{
"kid": "../../path/to/file",
"typ": "JWT",
"alg": "HS256",
"k": "asGsADas3421-dfh9DGN-AFDFDbasfd8-anfjkvc"
}
如果服务器还支持使用对称算法签名的 JWT,则这尤其危险。在这种情况下,攻击者可能会将 kid
参数指向可预测的静态文件,然后使用与此文件内容匹配的密钥对 JWT 进行签名。
理论上,您可以对任何文件执行此作,但最简单的方法之一是使用 /dev/null
,它存在于大多数 Linux 系统上。由于这是一个空文件,因此读取它将返回一个空字符串。因此,使用空字符串对令牌进行签名将产生有效的签名。
注意
如果您使用的是 JWT Editor 扩展,请注意,这不允许您使用空字符串对令牌进行签名。但是,由于扩展中存在 bug,您可以通过使用 Base64 编码的 null 字节来解决此问题。
如果服务器将其验证密钥存储在数据库中,kid
标头参数也是 SQL 注入攻击的潜在载体。
8.4 其他有趣的 JWT 标头参数
攻击者也可能对以下标头参数感兴趣:
-
cty(内容类型)- 有时用于声明 JWT 负载中内容的媒体类型。这通常在 Headers 中省略,但底层解析库可能仍然支持它。如果您找到了绕过签名验证的方法,则可以尝试注入
cty
标头以将内容类型更改为text/xml
或application/x-java-serialized-object
,这可能会为 XXE 和反序列化攻击启用新的向量。 -
x5c(X.509 证书链)- 有时用于传递 X.509 公钥证书或用于对 JWT 进行数字签名的密钥的证书链。此标头参数可用于注入自签名证书,类似于上面讨论的 jwk 标头注入攻击。由于 X.509 格式及其扩展的复杂性,解析这些证书也可能引入漏洞。这些攻击的详细信息超出了这些材料的范围,但有关更多详细信息,请查看 CVE-2017-2800 和 CVE-2018-2633。
9. JWT 算法混淆
即使服务器使用您无法暴力破解的强大密钥,您仍然可以通过使用开发人员没有预料到的算法对令牌进行签名来伪造有效的 JWT。这称为算法混淆攻击。
当攻击者能够使用与网站开发人员预期不同的算法强制服务器验证JSON Web令牌(JWT)的签名时,就会发生算法混淆攻击(也称为密钥混淆攻击)。如果这种情况处理不当,这可能会使攻击者伪造包含任意值的有效JWT,而无需知道服务器的秘密签名密钥。
9.1 对称与非对称算法
JWT可以使用一系列不同的算法进行签名。其中一些,例如HS256(HMAC+SHA-256)使用“对称”密钥。这意味着服务器使用单个密钥来签署和验证令牌。显然,这需要保密,就像密码一样。
其他算法,例如RS256(RSA+SHA-256)使用“非对称”密钥对。这包括服务器用于对令牌进行签名的私钥和可用于验证签名的数学相关公钥。
顾名思义,私钥必须保密,但公钥通常是共享的,以便任何人都可以验证服务器颁发的令牌的签名。
9.2 算法混淆漏洞是如何产生的?
算法混淆漏洞通常是由于 JWT 库的实现存在缺陷而出现的。尽管实际的验证过程因使用的算法而异,但许多库都提供了单一的、与算法无关的方法来验证签名。这些方法依赖于令牌标头中的 alg
参数来确定它们应执行的验证类型。
以下伪代码显示了此通用 verify()
方法的声明在 JWT 库中可能是什么样子的简化示例:
function verify(token, secretOrPublicKey){
algorithm = token.getAlgHeader();
if(algorithm == "RS256"){
// Use the provided key as an RSA public key
} else if (algorithm == "HS256"){
// Use the provided key as an HMAC secret key
}
}
当随后使用此方法的网站开发人员假设它将仅处理使用像 RS256 这样的非对称算法签名的 JSON Web 令牌(JWT)时,问题就会出现。由于这个错误的假设,他们可能会始终向该方法传递一个固定的公钥,如下所示:
publicKey = <public-key-of-server>;
token = request.getCookie("session");
verify(token, publicKey);
在这种情况下,如果服务器接收到使用对称算法(如 HS256)签名的令牌,该库的通用verify()
方法将把公钥视为 HMAC 密钥。这意味着攻击者可以使用 HS256 和公钥对令牌进行签名,而服务器将使用相同的公钥来验证签名。
注意
用于对令牌进行签名的公钥必须与服务器上存储的公钥完全相同。这包括使用相同的格式(例如 X.509 PEM)和保留任何非打印字符(如换行符)。在实践中,您可能需要尝试不同的格式才能使此攻击发挥作用。
9.3 执行算法混淆
算法混淆攻击通常涉及以下高级步骤:
-
获取服务器的公钥
-
将公钥转换为合适的格式
-
创建恶意 JWT,并修改有效负载并将
alg
标头设置为 HS256。 -
使用 HS256 对令牌进行签名,使用公钥作为密钥。
在本节中,我们将更详细地介绍此过程,演示如何使用 Burp Suite 执行此类攻击。
第 1 步 - 获取服务器的公钥
例如,服务器有时会通过映射到 /jwks.json
或 /.well-known/jwks.json
的标准端点将其公有密钥作为 JSON Web 密钥 (JWK) 对象公开。这些可以存储在称为 keys
的 JWK 数组中。这称为 JWK 集。
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
"n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
},
{
"kty": "RSA",
"e": "AQAB",
"kid": "d8fDFo-fS9-faS14a9-ASf99sa-7c1Ad5abA",
"n": "fc3f-yy1wpYmffgXBxhAUJzHql79gNNQ_cb33HocCuJolwDqmk6GPM4Y_qTVX67WhsN3JvaFYw-dfg6DH-asAScw"
}
]
}
即使密钥未公开,您也可以从一对现有 JWT 中提取它。
第 2 步 - 将公钥转换为合适的格式
尽管服务器可能会以 JWK 格式公开其公钥,但在验证令牌的签名时,它将使用其本地文件系统或数据库中的密钥副本。这可能以不同的格式存储。
为了使攻击起作用,用于对 JWT 进行签名的密钥版本必须与服务器的本地副本相同。除了采用相同的格式外,每个字节都必须匹配,包括任何非打印字符。
对于此示例,我们假设我们需要 X.509 PEM 格式的密钥。您可以使用 Burp 中的 JWT 编辑器扩展将 JWK 转换为 PEM,如下所示:
-
加载扩展后,在 Burp 的主选项卡栏中,转到 JWT 编辑器键选项卡。
-
单击 New RSA Key。在对话框中,粘贴您之前获取的 JWK。
-
选择 PEM 单选按钮并复制生成的 PEM 密钥。
-
转到 Decoder 选项卡并对 PEM 进行 Base64 编码。
-
返回到 JWT 编辑器密钥选项卡,然后单击新建对称密钥。
-
在对话框中,单击 Generate 以生成 JWK 格式的新密钥。
-
将
k
参数的生成值替换为您刚刚复制的 Base64 编码的 PEM 密钥。 -
保存密钥。
第 3 步 - 修改 JWT
获得合适格式的公钥后,您可以根据需要修改 JWT。只需确保 alg 标头设置为 HS256 即可。
第 4 步 - 使用公钥对 JWT 进行签名
使用 HS256 算法对令牌进行签名,并将 RSA 公钥作为密钥。
9.4 从现有令牌派生公钥
如果公钥不容易获得,你仍然可以通过从一对现有的 JSON Web Token(JWT)中推导密钥来测试算法混淆。这个过程使用诸如jwt_forgery.py
这样的工具相对简单。你可以在rsa_sign2n
GitHub 仓库(https://github.com/silentsignal/rsa_sign2n
)上找到这个工具以及其他一些有用的脚本。
此工具的简化版本,您可以将其作为单个命令运行:
docker run --rm -it portswigger/sig2n <token1> <token2>
注意
您需要 Docker CLI 来运行该工具的任一版本。首次运行此命令时,它将自动从 Docker Hub 拉取镜像,这可能需要几分钟时间。
这使用你提供的 JSON Web 令牌(JWT)来计算n
的一个或多个可能值。不用太担心这意味着什么——你只需要知道这些值中只有一个与服务器密钥使用的n
值匹配。对于每个可能的值,脚本输出:
-
X.509 和 PKCS1 格式的 Base64 编码的 PEM 密钥。
-
使用这些密钥中的每一个签名的伪造 JWT。
要识别正确的密钥,请使用 Burp Repeater 发送包含每个伪造 JWT 的请求。服务器将只接受其中一个。然后,您可以使用匹配密钥来构建算法混淆攻击。
有关此过程如何工作的更多信息,以及如何使用标准 jwt_forgery.py
工具的详细信息,请参阅存储库中提供的文档(https://github.com/silentsignal/rsa_sign2n
)。
10. 如何防止 JWT 攻击
您可以通过采取以下高级措施来保护自己的网站免受我们涵盖的许多攻击:
-
使用最新的库来处理 JWT,并确保您的开发人员完全了解其工作原理以及任何安全隐患。现代库使您更难在不安全的情况下无意中实现它们,但由于相关规范固有的灵活性,这并非万无一失。
-
确保对收到的任何 JWT 执行可靠的签名验证,并考虑边缘情况,例如使用意外算法签名的 JWT。
-
对
jku
标头实施严格的允许主机白名单。 -
确保您不易受到路径遍历或通过
kid
标头参数注入的攻击。
10.1 JWT 处理的其他最佳实践
虽然严格来说,在应用程序中使用 JSON Web Token(JWT)时遵循以下最佳实践并非完全必要,但为了避免引入漏洞,我们建议这样做:
-
始终为您发行的任何令牌设置到期日期。
-
尽可能避免在 URL 参数中发送令牌。
-
包括
aud
(audience) 声明(或类似声明)以指定令牌的预期接收者。这可以防止它在不同的网站上使用。 -
允许颁发服务器撤销令牌(例如,在注销时)。