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

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

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

实际上,这个问题适用于所有基于令牌的身份验证。

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


当前回答

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

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

令牌将改变每个请求。

其他回答

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

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

接下来,任何形式的身份验证(是否使用jwt)都可能受到MitM攻击(中间人)的攻击。当攻击者在你通过互联网发出请求时可以查看你的网络流量时,就会发生这些攻击。这是你的ISP可以看到的,美国国家安全局,等等。

这就是SSL帮助防止的:通过加密您的网络流量从您的计算机->一些服务器认证时,监视您的网络流量的第三方无法看到您的令牌,密码,或任何类似的东西,除非他们以某种方式能够获得服务器的私有SSL密钥的副本(不太可能)。这就是SSL对于所有形式的身份验证都是强制性的原因。

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

这就是协议的用武之地。

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

然而,jwt本身与“安全性”无关。从所有意图和目的来看,jwt或多或少与API密钥相同:只是用于对某个服务器进行身份验证的随机字符串。

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

OAuth2的工作方式是为客户端提供临时令牌(如jwt !),仅用于短时间的身份验证!

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

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

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

希望这有助于^^

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

要做到这一点,你应该总是发出短期令牌(取决于大多数情况下,在我的应用程序中,我实际上将exp声明设置为30分钟,ttl为3天,所以你可以刷新这个令牌,只要它的ttl仍然有效,令牌还没有被列入黑名单)

对于身份验证服务,为了使令牌失效,我喜欢在前面使用内存缓存层(在我的情况下是redis)作为JWT黑名单/禁令列表,这取决于一些标准: (我知道这违反了RESTful哲学,但是存储的文档真的是短命的,因为我将它们的剩余生存时间-ttl声明列入黑名单-)

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

If user.password or user.email has been updated (requires password confirmation), auth service returns a refreshed token and invalidates (blacklist) previous one(s), so if your client detects that user's identity has been compromised somehow, you can ask that user to change its password. If you don't want to use the blacklist for it, you can (but I don't encourage you to) validate the iat (issued at) claim against user.updated_at field (if jwt.iat < user.updated_at then JWT is not valid). User deliberately logged out.

最后,像所有人一样,正常地验证令牌。

注意2:我建议为jti声明生成并使用一个UUID令牌,而不是使用令牌本身(它真的很长)作为缓存的键。这很好,我认为(不确定,因为它刚刚出现在我的脑海中)你可以使用相同的UUID作为CSRF令牌,通过返回一个安全/非http-only cookie,并使用js正确实现X-XSRF-TOKEN头。这样就避免了为CSRF检查创建另一个令牌的计算工作。

对不起,我来晚了一点,但我有类似的担忧,现在想在同样的问题上贡献一些东西。

1) rdegges补充了一个很好的观点,即JWT与“安全”无关,只是验证,如果有人搞砸了有效载荷或没有(签名);SSL有助于防止入侵。

2)现在,如果ssl也以某种方式被破坏,任何窃听者都可以窃取我们的持名令牌(JWT)并模仿真正的用户,下一个可以做的步骤是,从客户端寻求JWT的“持有证明”。

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

我参考了占有证明的文章,并对这种方法深信不疑。

如果能有所贡献,我将非常高兴。

干杯(y)

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

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

令牌将改变每个请求。

一旦代币被盗,游戏就结束了。 然而,有一种方法可以使使用被盗的令牌变得更加困难。

查阅https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html#token-sidejacking。

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

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