JWT 的危险性及其替代方案

2025-05-26

JWT 的危险性及其替代方案

介绍

JSON Web Tokens (JWT) 是现代软件应用程序中用于 Web 身份验证和用户会话管理的最常用令牌。关于 JWT 带来的好处或优势的信息不胜枚举,然而,很少有开发人员和软件架构师了解使用 JWT 令牌的潜在风险和低效性。

在本文中,我们将讨论如果管理不善,JWT 如何使网站容易受到各种高安全威胁和攻击。由于 JWT 广泛应用于身份验证、会话管理和访问控制技术,这些漏洞可能会危及整个网站及其用户。

在深入了解细节之前,让我们先概述一下 JWT 以及它如何成为软件开发人员的标准。

什么是 JWT?

JSON Web 令牌 (JWT)是一种标准化格式,用于在系统之间安全地传输经过加密签名的 JSON 数据。它们可以包含任何类型的数据,但最常用于在身份验证、会话管理和访问控制过程中传输有关用户的数据(“声明”)。

与传统的会话令牌不同,服务器所需的所有数据都保存在客户端的 JWT 中。因此,对于分布式网站,当用户需要与众多后端服务器无缝交互时,JWT 是一种常见的解决方案。

JWT 由以下三部分组成:标头、有效负载和签名。标头和有效负载是经过 base64url 编码的 JSON 对象,可以从令牌中解码并显示信息。标头包含有关令牌的信息,即元数据,例如令牌的类型(即 JWT)以及所使用的签名算法(例如HMAC、SHA256RSA)。有效负载包含用户的真实“声明”。有效负载的内容没有任何限制,但需要注意的是,JWT 未加密。

JWT 的组件

因此,我们放入令牌中的任何信息仍然会被任何拦截它的人查看。因此,任何基于 JWT 机制的安全性都严重依赖于加密签名。

签名,即消息认证码(MAC),是 JWT 的最后一个组成部分。只有同时拥有有效载荷(包括头部)和密钥的人才能生成 JWT 签名。

由于签名是直接从令牌的其余部分获得的,因此改变标头或有效负载的单个字节会导致签名不正确。

如果不知道服务器的秘密签名密钥,就不可能为给定的标头或有效负载生成正确的签名。

JWT 中的每个部分都由点分隔,如下所示:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Enter fullscreen mode Exit fullscreen mode

解码可揭示如下信息:

标头:

{
  "alg": "HS256",
  "typ": "JWT"
}
Enter fullscreen mode Exit fullscreen mode

有效载荷:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
Enter fullscreen mode Exit fullscreen mode

签名:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),

your-256-bit-secret

)
Enter fullscreen mode Exit fullscreen mode

解码 JWT

我们可以看到,签名确实是 JWT 的关键部分!

签名允许完全无状态的服务器通过查看请求本身中存在的 JWT 令牌来确定 HTTP 请求属于特定用户,而不是强制在每次发出请求时发送密码。

对于进一步的用户操作,服务器仅验证签名部分,获取用户信息,并允许用户执行操作。因此,完全避免了数据库调用。

但是,关于 JWT 令牌,还有一件事你应该知道。那就是它有一个有效期,用于自毁。有效期通常设置为 5 到 30 分钟。而且由于它是自包含的,因此很难撤销/使其失效/更新。这才是问题的根源。下一节我们将详细探讨这一点。

JWT 为何会如此危险?

虽然 JWT 省去了数据库查找的环节,但它也带来了安全隐患和其他一些复杂性。安全性是二元的——要么安全,要么不安全。因此,在用户会话中使用 JWT 是危险的。

JWT 最大的问题是,令牌在过期前一直有效,并且服务器无法轻易撤销它。这在以下情况下可能极其危险:

注销并不会真正将您从系统中注销。即使您已注销,JWT 令牌仍会在其设定的到期期限内继续有效。这意味着,如果有人在此期间获得了该令牌的访问权限,他们就可以继续访问它,直到令牌过期。

同样,您不能因为审核或任何原因而阻止任何用户进入系统,因为他们将继续有权访问服务器,直到令牌过期。

假设用户原本是管理员,但被降级为权限较低的普通用户。同样,降级不会立即生效,在令牌过期之前,该用户仍将保持管理员身份。

由于 JWT 通常不加密,任何能够执行中间人攻击并嗅探 JWT 的人现在都可以访问您的身份验证凭据。由于 MITM 攻击只需在服务器-客户端连接上进行,因此这变得更加容易。

此外,许多实现 JWT 的库都存在许多安全问题。此外,许多实际程序需要服务器保存用户的 IP 地址,并跟踪 API 以进行速率限制和 IP 白名单设置。因此,无论如何,您都需要使用一个速度极快的数据库。认为使用 JWT 会使您的应用无状态是不现实的。

替代方案

一种典型的解决方案是维护一个“已撤销令牌”的数据库,并在每次调用时进行验证。如果令牌在该已撤销列表中,则阻止用户执行后续操作。但是,现在您需要额外调用数据库来检查令牌是否已被撤销,这完全违背了 JWT 的初衷。

答案并非完全避免出于会话原因使用 JWT。相反,我们应该采用传统但久经考验的方法。通过使用 Redis 等解决方案以及 JWT,使数据库查找速度极快(亚毫秒级),无需进行额外的调用,这样我们既能享受 JWT 的优势,又能消除前面讨论的大部分安全威胁。

在这个场景下,如果 JWT 验证成功,服务器仍然会去 Redis 那里再次核对信息。但如果 JWT 验证失败,则无需再去 Redis 数据库查询。

该技术的另一个优点是,您可以在前端和后端使用现有的 JWT 库,而无需开发自己在 Redis 中存储数据的自定义方式。

结论

在本文中,我们了解了 JWT 是什么以及如何使用它们进行身份验证。JWT 只是 JSON 格式的有效负载,具有易于验证且不可伪造的签名。我们还讨论了 JWT 处理不当可能带来的漏洞,以及可以使用的替代方案。

本文就到这里。如果您想联系我,请点击以下链接:

LinkedIn | GitHub | Twitter

文章来源:https://dev.to/pragativerma18/how-jwts-could-be-dangerous-and-its-alternatives-3k3j
PREV
释放 API 分页的力量:最佳实践和策略
NEXT
最流行的 API 类型指南:REST、SOAP、GraphQL 和 gRPC