JWT中应该使用什么样的“秘密”?

37
我将在使用Java-Jersey开发的REST API中应用JWT。我正在使用这个JWT库 - https://github.com/auth0/java-jwt 我有几个关于JWT-Secret的问题:
  1. 这个秘钥必须是唯一的吗?
  2. 我是否应该使用用户密码的哈希版本作为密钥?(那么它也不是唯一的)因为当用户更改密码时,他的令牌将自动失效。
3个回答

34
  1. 这个Secret需要唯一吗?

它应该是对于您的应用程序是唯一的 - 毕竟这是一个秘密,但对于每个令牌来说并不唯一。相反,您应该在任何给定时间内拥有相对较少的秘密密钥(例如通常只有一个密钥,但在从一个密钥旋转到下一个密钥时会有短暂的两个密钥)。

  1. 我应该使用用户密码的哈希版本作为密钥吗?

不行,有两个原因:

  1. 假设您的用户有一个相对不安全的密码,像GoPackers123。在您的密钥中使用密码意味着某人可以轻松地测试给定的潜在密码,以查看它是否产生正确的签名; 更重要的是,他们可以轻松地测试大量的潜在密码,以查看是否有任何一个给出了正确的签名。这是一种离线攻击,所以您甚至不会知道它发生了。
  2. 这将要求您将所有用户的密码哈希分发到每个需要保存密钥的系统中。如果您有超过一定数量的用户,这将成为秘密分发机制的负担。

1
通常只有一个密钥,这是指每个人都可以只有一个密钥吗?或者您的意思是每个用户需要分配一个密钥直到他们注销,但在那个时候有100个用户将有100个密钥?另外最后一个问题,如果两个人拥有相同的秘密,是否会导致冲突,使得A看到B的记录等等? - PeakGen
2
@PeakGen:你不需要与用户共享秘密,所以你不需要为不同的用户设置不同的秘密。但是你确实需要定期更换密钥;你可以为每个人使用同一个密钥,但不能永远使用同一个密钥。 - ruakh
谢谢,另一个问题。我在java-jwt中使用了一个硬编码的 secretHS256。我注意到所有用户都得到了相同的 token。API使用此令牌进行安全保护。这是正常行为吗? - PeakGen
2
@PeakGen:应该分别发布不同的问题,简而言之:不,这不正常。你的令牌应包括像“exp”和“sub”这样的声明来限制生命周期并区分用户;因此,没有两个令牌应该是相同的。 - ruakh

18
JWT和java-jwt库支持对称和非对称算法来进行签名:
- 如果你选择使用对称算法,比如HS256,你只需要一个密钥用于签名和验证签名。 - 如果你选择使用非对称算法,比如RS256,你需要一个私钥和一个公钥。请在服务器上保护好私钥并用它来签署令牌,使用公钥来验证签名(公钥也可以与需要验证签名的人共享)。
永远不要分享用于签署令牌的密钥!
同时,你可以为签署令牌设置一组不同的密钥。在这种情况下,kid头参数可用于指示用于签署令牌的密钥。该声明应携带密钥标识符而不是密钥本身。

请参考答案了解有关kid声明的更多详细信息。


好的,哪一个更好?HS256还是RSA256 - PeakGen
3
@PeakGen 这个问题应该是:“哪个对我的应用程序最好?” 答案是:“这取决于你的需求。” 如果你想让客户端验证签名,请选择RS256。否则,选择HS256。这个答案可能会有帮助。 - cassiomolin
谢谢。我相信HS256是我要走的路,因为我不会向用户提供任何密钥,而且他们也没有使用这样的密钥的必要。还有一个问题,我在java-jwt中使用了一个硬编码的secretHS256,我注意到我的所有用户都得到了相同的token。该API由此令牌保护。这是正常的行为吗? - PeakGen
当用户登录时,令牌会被生成。我正在使用相同的 secretHS256。有10个用户。当他们登录时,系统为每个人生成了相同的令牌,因为密钥是相同的。我认为这是正常的方式? - PeakGen
为什么不使用随机数?[a]您无需配置,[b]如果服务器重新启动,所有JWT都将失效。 - PeterT
显示剩余4条评论

2
使用RSA256,即使用私钥/公钥对(不需要“密钥”)。 这样,您可以将私钥保持秘密和安全(仅用于签署令牌),并且您可以使用公钥验证签名是否正确。 您可以将公钥提供给任何需要验证令牌签名的人或服务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接