如果JWT被盗怎么办?


201

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

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

但是,如果有一个窃听者看到请求并窃取令牌怎么办?那他就能伪造我的身份要求吗?

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

如何预防呢?像HTTPS这样的安全通道?


1
这就是令牌通常仅在短时间内有效的原因。是的,如果您担心数据的机密性,则应该使用HTTPS。
乔纳森·莱因哈特

4
@JonathonReinhart但是,如果令牌很快过期,我的客户将不得不通过不时重新认证自己来获得新令牌。是不是很乏味?
smwikipedia

@JonathonReinhart我想我明白为什么令牌是短暂的。因此,服务器不需要跟踪令牌的到期时间,因此可以为可伸缩性让路。这有点一trade-offhaving finer control of token expirationhaving better scalability
smwikipedia 2015年

2
这还能帮上忙吗?-“检测令牌盗用的常见安全机制是跟踪请求IP地址的来源。” -在此处的最后一部分中有详细介绍-firebase.google.com/docs/auth/admin/manage-sessions
Ula,

3
从理论上讲,不可能防止令牌被盗。我们能做的最好的事情就是检测到发生了这种情况,然后尽快撤消会话。最好的检测方法是使用旋转刷新令牌(如RFC 6819所建议)。下面是说明对此进行了详细一个博客:supertokens.io/blog/...
RISHABH波达

Answers:


284

我是一个节点库的作者,该库在相当深度的地方处理身份验证express-stormpath,因此在这里我将介绍一些信息。

首先,JWT通常加密。尽管有一种加密JWT的方法(请参阅:JWEs),但实际上由于很多原因,这种方法并不常见。

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

SSL可以防止此情况的发生:通过对计算机中的网络流量进行加密->身份验证时使用某些服务器,监视您网络流量的第三方无法看到您的令牌,密码或类似内容,除非它们能够以某种方式获取服务器的私有SSL密钥的副本(不太可能)。这就是SSL对于所有形式的身份验证都是强制性的原因。

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

现在,这就是协议的来源。

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

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

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

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

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

使用OAuth2,您必须经常通过提供用户名/密码或API凭据,然后通过交换令牌来重新认证自己。

因为此过程不时发生,所以您的令牌会经常更改,这使得攻击者更难不断地冒充您,而不会遇到麻烦。

希望这可以帮助^^


3
下一篇文章的作者认为,JWT的一个缺点是,从被盗的JWT中恢复的唯一方法是生成一个新的密钥对并有效地注销所有用户。鉴于会话ID存储在数据库中,该网站只能删除受影响用户的会话并将其注销所有设备。我不确定OAuth2如何适合这里的图片,或者它是否有助于减轻呈现的缺点。medium.com/@rahulgolwalkar/…–
Marcel

4
作者不正确。您可以使用多种设计模式来使令牌无效。但是总的来说:将JWT用于任何形式的身份验证是一个坏主意。使用带有嵌入了经过加密签名的会话想法的会话cookie效率要高得多。
rdegges

1
@rdegges请告诉我JWT对于身份验证来说是个坏主意吗?以及我如何使用您在上面的评论中提到的会话cookie?
noman tufail

6
输入单个响应太长了。如果您想了解更多信息,我已就此主题进行了详细的演讲。您可以在线查看我的幻灯片:Speakerdeck.com/rdegges/jwts-suck-and-are-stupid
rdegges

2
从理论上讲,不可能防止令牌被盗。我们能做的最好的事情就是检测到发生了这种情况,然后尽快撤消会话。最好的检测方法是使用旋转刷新令牌(如RFC 6819所建议)。下面是说明对此进行了详细一个博客:supertokens.io/blog/...
RISHABH波达

31

我知道这是一个老问题,但我认为我可以在这里降低$ 0.50,也许有人可以改善或提出理由完全拒绝我的方法。我正在通过HTTPS(ofc)在RESTful API中使用JWT。

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

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

注意:列入黑名单的令牌无法自动刷新

  • 如果user.passworduser.email已更新(需要密码确认),则身份验证服务将返回刷新的令牌并使先前的令牌无效(黑名单),因此,如果您的客户端检测到用户身份已以某种方式受到破坏,则可以要求该用户更改其密码。 。如果您不想使用黑名单,则可以(但我不鼓励您iat)针对user.updated_at字段验证(发出于)索赔(如果jwt.iat < user.updated_atJWT无效)。
  • 用户故意注销。

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

注意2:建议不要为令牌声明生成并使用UUID令牌,而不要使用令牌本身(这确实很长)作为缓存的键jti。这样做很好,而且我认为(不确定,因为它只是在我脑海中浮现出来),您还可以使用与CSRF令牌相同的UUID,方法是返回一个secure/ non-http-onlycookie并X-XSRF-TOKEN使用js 正确实现标头。这样,您就避免了为CSRF检查创建另一个令牌的计算工作。


9
贡献您的想法永远不会太晚。感谢您的回复。
smwikipedia

2
如果您在服务器上存储了一个需要检查每个请求的黑名单,那么为什么不简单地使用普通的旧会话呢?
富兰克林·于

@FranklinYu黑名单比完整的会话存储更“便宜”。由于您存储的是短暂的键值对象(取决于它们的剩余生存时间,应该很短),并且这种情况仅发生在退出操作和使令牌无效的操作上,因此并非每个令牌都是存储的
Frondor

2
可以便宜吗?首先,如果您仍在服务器端存储任何内容,那么您将无法享受JWT声称的“可伸缩性”优势,因为在执行任何操作之前,所有应用程序服务器仍然需要与之对话的中央黑名单服务器。如果由于快速到期而只需要存储1k黑名单,则可以对会话执行相同操作,因此只需要存储1k会话。
富兰克林·于

3
我喜欢这种方法。实际上,您不必检查每个请求的黑名单,只需检查在JWT过期(可以从令牌本身读取)之后直到TTL期间发生的请求。在“标准”用例中,最多应该在给定令牌的生存期内发生一次。刷新后,您可能会拒绝以后的任何刷新请求。感谢@Frondor
John Ackerman

7

抱歉,在此方面晚了一点,但是有类似的问题,现在想在同一点上有所作为。

1)rdegges补充了一个很好的观点,即JWT与“安全性”无关,并且仅验证是否有人弄乱了有效载荷(签名);ssl有助于防止违规。

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

3)现在,通过这种方法,JWT的演示者拥有一个特定的所有权证明(POP)密钥,接收者可以通过密码确认该请求是否来自同一真实用户。

为此,我提到了所有权证明一文,并对方法深信不疑。

如果能够做出任何贡献,我将很高兴。

干杯(y)


0

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


这是一种可能的解决方案,但对于防火墙后的客户端而言,通常是从地址池中选择IP地址,并且该IP地址可以随时更改。
SpeedOfSpin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.