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

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

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

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

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


当前回答

我知道这是一个老问题,但我认为我可以在这里放弃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检查创建另一个令牌的计算工作。

其他回答

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

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

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

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

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

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

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

令牌将改变每个请求。

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

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

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

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

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

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

干杯(y)

我知道这是一个老问题,但我认为我可以在这里放弃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检查创建另一个令牌的计算工作。