我可以防止对我签名的 JWT 的重放攻击吗?

信息安全 http 休息 jwt json
2021-08-22 19:28:53

我使用 JWT 在 Laravel 中通过 HTTP 实现了无状态身份验证。

  1. 我从前端发送我的用户名/密码。
  2. 服务器对用户进行身份验证,发回带有到期时间的签名 JWT。
    • 我正在使用 HS512 算法使用私钥进行签名(仅对服务器可用)。
  3. 前端存储令牌以供将来请求。
  4. 前端发送包含令牌的下一个请求。
  5. 服务器验证令牌是否有效且未过期,如果两者都是,则让操作继续。
  6. 当令牌过期时,服务器会发送一条“注销”消息。

所有这些通信都通过 HTTPS 进行。

所以我可以从以下几点看出这是安全的:

  • 由于 HTTPS,攻击者无法嗅探流量并窃取 JWT 令牌。
  • 攻击者无法生成和发送任何奇怪的令牌,因为服务器使用其私钥验证签名。
  • 攻击者无法修改发出请求的用户(以及请求者的角色和权限),因为sub这是令牌中声明的一部分。

但是,我有两个问题

  1. 如果用户的计算机或移动设备上存在病毒,并且它从 RAM 或浏览器中窃取了有效令牌怎么办。然后它可以发送更多请求,并且它们将被接受。有什么办法可以防止这种情况发生吗?
  2. 还有另一种我没有看到的攻击这个系统的方法吗?
4个回答

此处jti描述声明是用于防止进一步重放攻击的可选机制。从规范:

4.1.7. “jti”(JWT ID)声明

“jti”(JWT ID)声明为 JWT 提供了唯一标识符。标识符值的分配方式必须确保相同的值被意外分配给不同的数据对象的可能性可以忽略不计;如果应用程序使用多个发行者,则必须防止不同发行者产生的值之间的冲突。“jti”声明可用于防止 JWT 被重放。“jti”值是区分大小写的字符串。使用此声明是可选的。

这最终会使您的服务器有状态,但如果您检测到异常行为或用户报告可疑活动,它会阻止无限重放。考虑以下场景。

  1. 用户登录。您的服务器生成 JWT,并存储签名以及一些元数据(用户 ID 和发出请求的客户端的类型,可能还有jti)。
  2. 用户报告可疑行为。
  3. 应用程序通过删除附加到该用户的后端存储中的所有 JWT,“注销”所有设备的用户。现在应用程序可以说“我知道你有一个有效的签名,但我不接受它,因为它不是我创建的。”
    • 如果您的元数据足够精确,您可以使用jti附加信息,例如,仅将用户从给定设备中注销。

如上所述,这不可避免地会使您的服务器有状态。这也不能完全阻止重放攻击,但它可以在检测到此类攻击后进一步关闭此类攻击。

一种替代/附加方法可以在一定程度上彻底防止重放攻击,但有可能给用户带来不便。将用户的 IP 地址作为声明的一部分并在登录时存储元数据,并验证使用 JWT 的 IP 是否是您期望的。对于同时在家和咖啡店工作的用户来说,这可能会令人沮丧,但对于高安全性应用程序来说,这可能是可接受的要求。

如果在您的 Web 应用程序的同一上下文中执行代码,无论它是浏览器中 XSS 攻击的一部分,还是用户计算机上的某些恶意软件/病毒,都很难(不可能?)区分这些请求和您的请求。自己的。

如果攻击者可以访问计算机,他们也可以从您的应用程序正常请求到您的服务器中窃取数据。

潜在地,您可以进行一些服务器端入侵检测风格分析:例如检查大量请求或项目计数;强制执行一些自定义的引用方案,您可以在其中知道 Web 应用程序的哪些组件发出数据请求。那么当您检测到异常行为时可能会触发重新身份验证?您还需要一种服务器端的方式来使您的 JWT 超过exp嵌入在 JWT 中的内容。

JWT 在设计上是不记名令牌,因此拥有它的客户可以多次使用它。因此,如果您想保持会话管理无状态,那么您将不得不做出权衡。这篇关于有状态与无状态会话管理的文章很好地强调了这些差异。

如果您想保持更高级别的安全性,那么您需要使用不同的方法,例如使用签名方案或让 HTTPS 通过 TLS 处理它。

为什么不将日期时间作为有效负载和到期时间?您无需更改有效负载,应用程序逻辑可以使令牌过期。或者使用基于叶子性质的新秘密(类似于DUKPT),因此新令牌请求会使旧令牌无效。