ChatGPT解决这个技术问题 Extra ChatGPT

如果 JWT 被盗怎么办?

我正在尝试使用 JWT 为我的 RESTful API 实现无状态身份验证。

AFAIK,JWT 基本上是在 REST 调用期间作为 HTTP 标头传递的加密字符串。

但是如果有窃听者看到请求并窃取令牌怎么办?那他就可以用我的身份伪造请求了?

实际上,这种担忧适用于所有基于令牌的身份验证。

如何防止这种情况?像 HTTPS 这样的安全通道?

这就是为什么令牌通常只在短时间内有效。是的,如果您担心数据的机密性,您应该使用 HTTPS。
@JonathonReinhart 但是如果令牌很快到期,我的客户将不得不通过不时重新验证自己来获取新令牌。是不是有点乏味?
@JonathonReinhart 我想我明白为什么令牌是短暂的。因为那样,服务器不需要跟踪令牌的到期,从而为可伸缩性让路。它是一种介于 having finer control of token expirationhaving better scalability 之间的 trade-off
这也有帮助吗? - “用于检测令牌盗窃的常见安全机制是跟踪请求 IP 地址的来源。” - 在此处的最后一节中详细描述 - firebase.google.com/docs/auth/admin/manage-sessions
从理论上讲,不可能防止令牌盗窃。我们能做的最好的事情就是检测到这种情况已经发生,然后尽快撤销会话。最好的检测方法是使用旋转刷新令牌(如 RFC 6819 所建议的那样)。这是一个详细解释这一点的博客:supertokens.io/blog/…

C
Community

我是一个节点库的作者,该库处理相当深入的身份验证,express-stormpath,所以我将在这里附上一些信息。

首先,JWT 通常是加密的。虽然有一种加密 JWT 的方法(请参阅:JWEs),但由于许多原因,这在实践中并不常见。

接下来,任何形式的身份验证(使用或不使用 JWT)都会受到 MitM 攻击(中间人)攻击。当攻击者可以在您通过 Internet 发出请求时查看您的网络流量时,就会发生这些攻击。这是您的 ISP、NSA 等可以看到的内容。

这是 SSL 有助于防止的:通过加密来自您计算机的网络流量 -> 身份验证时的某些服务器,监控您的网络流量的第三方无法看到您的令牌、密码或类似的东西,除非他们能够以某种方式获取服务器的私有 SSL 密钥的副本(不太可能)。这就是所有形式的身份验证都必须使用 SSL 的原因。

但是,假设有人能够利用您的 SSL 并能够查看您的令牌:您的问题的答案是肯定的,攻击者将能够使用该令牌冒充您并向您的服务器发出请求。

现在,这就是协议的用武之地。

JWT 只是身份验证令牌的一种标准。它们几乎可以用于任何事情。 JWT 有点酷的原因是您可以在其中嵌入额外的信息,并且您可以验证没有人弄乱它(签名)。

但是,JWT 本身与“安全”无关。出于所有意图和目的,JWT 或多或少与 API 密钥相同:只是用于在某处对某些服务器进行身份验证的随机字符串。

使您的问题更有趣的是正在使用的协议(很可能是 OAuth2)。

OAuth2 的工作方式是,它旨在为客户端提供临时令牌(如 JWT!),仅在短时间内进行身份验证!

这个想法是,如果您的令牌被盗,攻击者只能在短时间内使用它。

使用 OAuth2,您必须经常通过提供您的用户名/密码或 API 凭据来重新对服务器进行身份验证,然后获取一个令牌作为交换。

因为这个过程时不时发生,你的代币会经常改变,这使得攻击者更难不断冒充你而不会遇到很大的麻烦。

希望这会有所帮助^^


以下文章的作者认为,JWT 的一个缺点是从被盗的 JWT 中恢复的唯一方法是生成一个新的密钥对并有效地注销所有用户。而使用存储在数据库中的会话 ID,网站只能删除受影响用户的会话并将他从所有设备中注销。我不确定 OAuth2 如何适合这里的图片,或者它是否有助于减轻所呈现的缺点。 medium.com/@rahulgolwalkar/…
作者不正确。您可以使用不同的设计模式来使令牌无效。但总的来说:将 JWT 用于任何类型的身份验证目的都是一个坏主意。使用嵌入了加密签名的会话想法的会话 cookie 效率更高。
@rdegges 请告诉我 JWT 对身份验证来说是个坏主意吗?以及我如何使用您在上面的评论中提到的会话 cookie?
这太长了,无法输入单个响应。如果您想了解更多信息,我已经就该主题进行了详细的讨论。您可以在线查看我的幻灯片:speakerdeck.com/rdegges/jwts-suck-and-are-stupid
从理论上讲,不可能防止令牌盗窃。我们能做的最好的事情就是检测到这种情况已经发生,然后尽快撤销会话。最好的检测方法是使用旋转刷新令牌(如 RFC 6819 所建议的那样)。这是一个详细解释这一点的博客:supertokens.io/blog/…
F
Frondor

我知道这是一个老问题,但我认为我可以在这里放弃我的 0.50 美元,也许有人可以改进或提供完全拒绝我的方法的论据。我在通过 HTTPS (ofc) 的 RESTful API 中使用 JWT。

为此,您应该始终发出短期令牌(取决于大多数情况,在我的应用中,我实际上将 exp 声明设置为 30 分钟,将 ttl 声明设置为 3 天,因此您可以刷新此令牌只要它的 ttl 仍然有效并且令牌未被列入黑名单

对于 authentication service,为了使令牌无效,我喜欢使用内存缓存层(在我的例子中为 redis)作为前面的 JWT blacklist/ban-list,具体取决于某些标准:(我知道它违反了 RESTful 哲学,但存储的文档确实是短暂的,因为我将它们的剩余生存时间列入黑名单 -ttl 声明 -)

注意:列入黑名单的令牌不能自动刷新

如果 user.password 或 user.email 已更新(需要密码确认),身份验证服务会返回一个刷新的令牌并使之前的令牌无效(黑名单),因此如果您的客户端检测到用户的身份已被某种方式泄露,您可以询问该用户更改其密码。如果您不想为此使用黑名单,您可以(但我不鼓励您)验证针对 user.updated_at 字段的 iat(发布于)声明(如果 jwt.iat < user.updated_at 则 JWT 是无效)。

用户故意退出。

最后,您像每个人一样正常验证令牌。

注意 2: 我建议不要使用令牌本身(它真的很长)作为缓存的键,而是为 jti 声明生成和使用 UUID 令牌。哪个好,我认为(不确定,因为它刚刚出现在我的脑海中)您也可以使用与 CSRF 令牌相同的 UUID,方法是返回一个 secure / non-http-only cookie 并正确实现 {4 } 标头使用 js。这样您就可以避免为 CSRF 检查创建另一个令牌的计算工作。


如果您在需要检查每个请求的服务器上存储了一个黑名单,为什么不简单地使用普通的旧会话呢?
@FranklinYu 黑名单比完整的会话存储“便宜”。由于您存储的是短期键值对象(取决于它们的剩余生存时间,这应该很短),并且这只发生在注销操作和使令牌无效的此类操作中,因此并非每个令牌都是存储的
能有多便宜?首先,如果您仍然在服务器端存储任何内容,那么您将无法享受 JWT 声称的“可扩展性”优势,因为仍然有一个中央黑名单服务器,所有应用程序服务器在执行任何操作之前都需要与之通信。如果由于快速过期只需要存储 1k 黑名单,您可以对会话执行相同操作,因此只需要存储 1k 会话。
我喜欢这种方法。您实际上不必检查每个请求的黑名单,只需检查 JWT 过期后(您可以从令牌本身读取)以及之后的 TTL 期间发生的请求。在“标准”用例中,这应该在给定令牌的生命周期中最多发生一次。刷新后,您可能会拒绝任何未来的刷新请求。谢谢@Frondor
y
yanky_cranky

抱歉在这方面有点晚了,但有类似的担忧,现在想为此做出贡献。

1) rdegges 添加了一个很好的观点,JWT 与“安全”无关,只是验证是否有人弄乱了有效负载(签名); ssl 有助于防止违规。

2)现在,如果 ssl 也以某种方式受到损害,任何窃听者都可以窃取我们的不记名令牌(JWT)并冒充真实用户,下一步可以做的是从客户端寻求 JWT 的“拥有证明” .

3) 现在,通过这种方法,JWT 的提交者拥有一个特定的 Proof-Of-Possession (POP) 密钥,接收者可以cryptographically确认请求是否来自同一真实用户。

我为此参考了 Proof of Possesion 文章,并且对这种方法深信不疑。

如果能够贡献任何东西,我会很高兴。

干杯(y)


a
aRvi

为了解决令牌被盗的问题,您将每个 JWT 映射到有效 IP 列表。

例如,当用户使用特定 IP 登录时,您可以将该 IP 添加为该 JWT 的有效 IP,并且当您从另一个 IP 获得此 JWT 的请求时(用户更改互联网或 JWT 被盗,或任何原因)您可以根据您的用例执行以下操作:

将 CSRF 令牌与用户令牌映射,以防万一它被盗,那么它的 CSRF 令牌将不匹配,因为您可以使该用户令牌无效。您可以向用户提供验证码以验证他是否是有效用户。如果他输入验证码,则将该 IP 添加到该 JWT 的有效列表中。您可以注销用户并发出新请求以再次登录。您可以提醒用户您的 IP 已更改或从其他位置请求。

建议是否可以改进。


您的直觉很好,但搜索的是“令牌绑定”,这会将 JWT 绑定到 TLS 会话。
不是一种有效的方法。我家wifi的公共IP几乎每天都在变化。意思是,我必须每天应用上面提到的三个点中的任何一个。
@Puspender这完全取决于用例,您希望保持事物的安全性,例如。银行网站通常使用这种方法,我猜 Discord 在每次登录时都会使用这种方法。
V
Venkatesh Vs

我们不能只添加请求生成此 JWT 令牌的初始主机的 ip 作为声明的一部分吗?现在,当 JWT 被盗并从另一台机器上使用时,当服务器验证此令牌时,我们可以验证请求的机器 ip 是否与作为声明一部分的一组匹配。这将不匹配,因此可以拒绝令牌。此外,如果用户尝试通过将自己的 ip 设置为令牌来操纵令牌,则令牌将在令牌被更改时被拒绝。


这是一种可能的解决方案,但对于防火墙后面的客户端来说,IP 地址通常是从地址池中挑选出来的,并且可以随时更改。
如果有转发代理怎么办?或者用户每次连接时都使用VPN。不值得接近。
移动用户也是一个问题。我的移动 IP 每天更改很多次。
仅适用于固定 IP 后面的设备。它也无法防止,比如 ColleagueA 从 ColleagueB 窃取 JWT(两个同事都在同一公共 IP 后面的办公网络上工作)
j
jksevend

一旦令牌被盗 - 游戏就结束了。但是,有一种方法可以使使用被盗令牌变得更加困难。

检查 https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html#token-sidejacking 以供参考。

基本上,您以十六进制创建一个 x 字节长的指纹,将其原始值存储在令牌中 - 使用例如 SHA-512 对指纹进行散列,并将散列后的指纹放入 httponly 安全 cookie 中。

现在,您不仅需要验证令牌的签名和过期日期,还需要验证 cookie 的存在并确保原始指纹值匹配。


M
Mendi Barel

客户端应使用用户密码的部分哈希值来加密客户端向服务器发送 http msg 的时间。这部分哈希也应该在创建令牌时使用一些服务器密钥加密到令牌中。

服务器可以解密http请求时间并验证短时间延迟。

令牌将更改每个请求。