JWT漏洞攻击详解

admin 2024年12月16日13:28:11评论34 views字数 4491阅读14分58秒阅读模式
什么是 JWT攻击

JWT 攻击涉及用户向服务器发送修改后的 JWT 以实现恶意目标。通过模拟已通过身份验证的其他用户来绕过身份验证和访问控制。

常见的 JWT 攻击类型:

  1. 敏感信息泄露:攻击者可能通过各种手段获取到 JWT 中包含的敏感信息,例如用户身份、权限等。
  2. 接受任意签名:如果服务器在验证 JWT 时没有正确检查签名,攻击者可以创建一个带有任意签名的 JWT 并获得未经授权的访问。
  3. 接受未签名的令牌:如果服务器允许未签名的 JWT,攻击者可以创建一个未签名的 JWT 并获得未经授权的访问。
  4. 暴力破解密钥:攻击者可以通过暴力破解的方式尝试猜测用于签名 JWT 的密钥。
  5. JWT 头部参数注入:攻击者可以通过篡改 JWT 头部的参数(如 alg、jwk、jku、kid 等)来绕过身份验证机制。
  6. 算法混淆攻击:攻击者可以通过混淆 JWT 使用的加密算法来绕过身份验证机制。
JWT 攻击的漏洞是如何产生的

JWT 漏洞通常是由于应用程序本身中的 JWT 处理有缺陷而出现的。即使在使用经过实战的库时,也可能会导致意外引入漏洞。

这种缺陷通常意味着 JWT 的签名未得到正确验证。使攻击者能够篡改通过令牌的有效负载传递给应用程序的值。即使签名经过可靠验证,它是否真的可信在很大程度上也取决于服务器的密钥是否保持机密。如果此密钥以某种方式泄露,或者可以被猜到或暴力破解,攻击者可以任何任意令牌生成有效签名,从而破坏整个机制。

利用有缺陷的 JWT 签名验证

服务器通常不存储有关它们颁发的 JWT 的任何信息。相反,每个令牌都是一个完全独立的实体。这种设计有几个优点,但也引入了一个基本问题:服务器实际上不知道令牌的原始内容,甚至不知道原始签名是什么。因此,如果服务器没有正确验证签名,则没有什么可以阻止攻击者对令牌的其余部分进行任意更改。

优点是

  • 无状态:服务器不需要存储会话信息,这增加了系统的可扩展性和可用性,减轻了服务端的压力。
  • 易于分布式部署:由于 JWT 是自包含的,可以在多个服务器之间共享,而不需要依赖中央存储。
  • 跨域支持:JWT 可以在不同域名之间传递,支持跨域身份验证和授权。

注:JWT 在分布式部署中的优势

由于 JWT 包含了所有必要的信息,服务器在验证 JWT 时不需要查询数据库或任何中央存储。这使得 JWT 非常适合在分布式系统中使用。

在传统的会话管理中,服务器需要维护每个用户的会话数据,这些数据通常存储在内存或数据库中。在分布式系统中,多个服务器实例需要共享会话数据,这通常通过集中式存储(如 Redis)或会话粘滞(session sticky)等技术来实现,增加了系统的复杂性和维护成本。

而JWT 不需要依赖中央存储。每个服务器实例都可以独立验证和处理 JWT,这大大简化了系统的架构和维护工作。所以 JWT 的无状态可以实现任何服务器实例都可以验证和处理用户请求,无需共享会话数据,

接受任意签名

JWT(JSON Web Token)库通常提供两种主要的方法来处理 JWT 令牌:验证令牌和解码令牌。验证令牌的方法(如 Node.js 库 jsonwebtoken 中的 verify() 方法)不仅解码 JWT,还会检查令牌的签名是否有效。确保了令牌的内容没有被篡改,并且令牌是由可信的发行者签发的。解码令牌的方法(如 Node.js 库 jsonwebtoken 中的 decode() 方法)只解码 JWT 的头部和有效载荷,而不验证签名。这意味着解码令牌的方法只能用于查看令牌的内容,而不能保证令牌的有效性和安全性。开发人员有时会混淆这两个方法,只将传入的令牌传递给 decode() 方法。这实际上意味着应用程序根本不验证签名。

接受没有签名的令牌

JWT 标头包含一个 alg 参数用于指示服务器应该使用哪种算法对令牌进行签名。也告诉服务器在验证签名时需要使用哪种算法(HS256、RS256)。

然而,这种机制本质上是有缺陷的,因为服务器必须默认信任来自令牌的用户可控输入。意味着攻击者可以通过操纵 alg 参数来影响服务器验证令牌的方式。

例如,攻击者可以将 alg 参数设置为 none,这表示所谓的“不安全的 JWT”,即令牌没有签名。尽管服务器通常会拒绝没有签名的令牌,但由于这种筛选依赖于字符串解析,攻击者有时可以使用经典的混淆技术(例如混合大小写和意外编码)来绕过这些筛选条件。

暴力破解密钥

某些签名算法(如 HS256 (HMAC + SHA-256))使用任意的独立字符串作为密钥。这是不容易破解的。但是可以创建任何标头和有效负载值的 JWT,然后使用密钥对令牌重新签名。

开发人员有时会使用一些开源系统或库,但是会忘记更改默认密钥(默认密钥通常是系统或库在初始化时自动生成的密钥。如某些库可能会使用固定的字符串作为默认密钥)或占位符密钥(用于在开发过程中模拟真实密钥的行为,不是随机生成的,而是使用简单的字符串或者其他容易识别的模式。例如,在示例代码中,可能会使用“secret”或者“password”作为占位符密钥)。甚至可能会复制和粘贴网上找到的代码片段,然后忘记更改作为示例提供的硬编码密钥(直接在代码中写入密钥。一旦代码被泄露,密钥也会随之暴露。硬编码密钥难以更改,因为每次更改都需要修改代码并重新部署)。在这种情况下,攻击者使用已知密钥的单词列表暴力破解服务器的密钥可能很简单。

JWT 标头参数注入

根据 JWS 规范,只有 alg 标头参数是必需的。但是它还有一些其他参数:

  • jwk(JSON Web 密钥)- 提供表示密钥的嵌入式 JSON 对象。
  • jku (JSON Web 密钥集 URL) - 提供一个 URL,服务器可以从该 URL 中获取包含正确密钥的一组密钥。
  • kid (Key ID) - 提供一个 ID,在有多个密钥可供选择的情况下,服务器可以使用该 ID 来识别正确的密钥。根据键的格式,这可能具有匹配的 kid 参数。

这些用户可控制的参数都告诉服务器在验证签名时使用哪个密钥。攻击者可能会利用这些来注入使用任意密钥(而不是服务器密钥)签名的修改后的 JWT。

通过 jwk 参数注入自签名 JWT

JSON Web 签名 (JWS) 规范描述了一个可选的 jwk 标头参数(JWK(JSON Web 密钥)是一种用于将密钥表示为 JSON 对象的标准化格式),服务器可以使用该参数将其公钥以 JWK 格式直接嵌入到令牌本身中。

一般情况下,服务器应仅使用有限的公钥白名单来验证 JWT 签名。但是,配置错误的服务器有时会使用 jwk 参数中嵌入的任何密钥。可以通过使用自己的 RSA 私有密钥对修改后的 JWT 进行签名,然后将匹配的公有密钥嵌入 jwk 标头来利用此行为。

通过 jku 参数注入自签名 JWT

某些服务器允许使用 jku (JWK Set URL) 标头参数来引用包含密钥的 JWK 集(一个 JSON 对象,其中包含表示不同键的 JWK 数组),而不是直接使用 jwk 标头参数嵌入公钥。验证签名时,服务器会从此 URL 获取相关密钥。

JWK(JSON Web Key)是一种用于表示公钥的 JSON 对象格式。JWK 集是一组 JWK 的集合,通常用于在不同系统之间共享公钥。许多网站会通过标准端点公开 JWK 集,并且只从受信任的域获取密钥。但有时可以利用 URL 解析差异来绕过此类过滤。例如,某些系统可能对 URL 的解析不够严格,导致可以使用不同的 URL 形式来访问相同的资源。这种情况下,攻击者可能会尝试构造特殊的 URL 来绕过域名过滤,从而获取本应受限的密钥。

通过 kid 参数注入自签名 JWT

服务器可以使用多个加密密钥对不同类型的数据进行签名,而不仅仅是 JWT。因此,JWT 的标头可能包含 kid (Key ID) 参数,该参数可帮助服务器在验证签名时识别要使用的密钥。验证密钥通常存储为 JWK 集,服务器可以简单地查找与 kid 令牌相同的 JWK。

kid 参数没有具体的结构,可以选择任意字符串,可以使用 kid 参数来指向数据库中的特定条目,甚至是文件的名称。

如果kid参数也容易受到目录遍历的攻击,则攻击者可能会强制服务器使用其文件系统中的任意文件作为验证密钥。

如果服务器还支持使用对称算法签名的 JWT,在这种情况下,攻击者可能会将 kid 参数指向可预测的静态文件,然后使用与此文件内容匹配的密钥对 JWT 进行签名。

可以对任何文件执行签名操作,但使用 /dev/null 是最简单的方法之一。由于 /dev/null 返回一个空字符串,因此使用它对令牌进行签名将产生有效的签名。(注:在 Linux 系统中,/dev/null 是一个特殊文件,通常被称为“黑洞”。任何写入 /dev/null 的数据都会被丢弃,而读取 /dev/null 则会返回一个空字符串。)

如果服务器将其验证密钥存储在数据库中,则 kid 标头参数也是 SQL 注入攻击的潜在载体。

JWT 标头参数

  • cty(内容类型)- 有时用于声明 JWT 负载中内容的媒体类型。这通常在 Headers 中省略,但底层解析库可能仍然支持它。如果您找到了绕过签名验证的方法,则可以尝试注入 cty 标头以将内容类型更改为 text/xml 或 application/x-java-serialized-object ,这可能会为 XXE 和反序列化攻击启用新的向量。
  • x5c(X.509 证书链)- 有时用于传递 X.509 公钥证书或用于对 JWT 进行数字签名的密钥的证书链。此标头参数可用于注入自签名证书,类似于上面讨论的 jwk 标头注入攻击。由于 X.509 格式及其扩展的复杂性,解析这些证书也可能引入漏洞。
JWT算法混淆攻击

算法混淆攻击(也称为密钥混淆攻击)是指攻击者能够强制服务器使用与网站开发人员不同的算法来验证 JSON Web 令牌 (JWT) 的签名。这可能使攻击者能够伪造包含任意值的有效 JWT,而无需知道服务器的秘密签名密钥。

算法混淆漏洞通常是由于 JWT 库的实现存在缺陷而出现的。尽管实际的验证过程因使用的算法而异,但许多库都提供了单一的、与算法无关的方法来验证签名。这些方法依赖于令牌标头中的 alg 参数来确定它们应执行的验证类型。

算法混淆攻击涉及的步骤:

  1. 获取服务器的公钥

    服务器有时会通过映射到 /jwks.json 或 /.well-known/jwks.json 的标准端点将其公有密钥作为 JSON Web 密钥 (JWK) 对象公开。这些可以存储在称为 keys 的 JWK 数组中。这称为 JWK 集(JWK 集是一个 JSON 对象,其中包含表示不同密钥的 JWK 数组。每个 JWK 对象代表一个单独的密钥,可以包括密钥类型、算法、使用场景等信息。)。即使密钥未公开,也可以从一对现有 JWT 中提取它。

  2. 将公钥转换为合适的格式

    服务器可能会以 JWK 格式公开其公钥,但在验证令牌的签名时,它将使用其本地文件系统或数据库中的密钥副本。这可能以不同的格式存储。为了使攻击起作用,用于对 JWT 进行签名的密钥版本必须与服务器的本地副本相同。除了采用相同的格式外,每个字节都必须匹配,包括任何非打印字符。

  3. 创建恶意 JWT,并修改有效负载,将 alg 标头设置为 HS256。

    获得合适格式的公钥后,可以根据需要修改 JWT。只需确保 alg 标头设置为 HS256 即可。

  4. 使用 HS256 对令牌进行签名,使用公钥作为密钥。

    使用 HS256 算法对令牌进行签名,并将 RSA 公钥作为密钥。

 

原文始发于微信公众号(老付话安全):JWT漏洞攻击详解

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月16日13:28:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JWT漏洞攻击详解https://cn-sec.com/archives/3511567.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息