【发布时间】:2016-09-26 11:52:34
【问题描述】:
更新:我已经结束了对这个问题的研究,并发布了一篇长篇博客文章来解释我的发现:The Unspoken Vulnerability of JWTs。我解释了使用 JWT 进行本地身份验证的巨大推动力如何遗漏了一个关键细节:必须保护签名密钥。我还解释说,除非您愿意竭尽全力保护密钥,否则最好通过 Oauth 委派身份验证或使用传统会话 ID。
我已经看到很多关于 JSON Web 令牌安全性的讨论——重放、撤销、数据透明度、令牌指定的算法、令牌加密、XSS、CSRF——但我没有看到任何关于由依赖于签名密钥。
如果有人破坏了服务器并获得了 JWT 签名密钥,在我看来,此人随后可以使用该密钥来伪造未过期的 JWT 并秘密获得访问权限。当然,服务器可以在每个请求上查找每个 JWT 以确认其有效性,但服务器完全使用 JWT,因此它们不必这样做。服务器可以确认 IP 地址,但如果 JWT 不可信,这也涉及查找,显然这样做会排除可靠的移动访问。
将此与基于会话 ID 的服务器入侵进行对比。如果此服务器正在对密码进行哈希处理,则攻击者必须在会话 ID 过期之前为每个用户单独获取和使用会话 ID。如果服务器只存储会话 ID 的哈希值,攻击者将不得不写入服务器以确保访问。无论如何,攻击者的优势似乎较小。
我发现一种使用 JWT 的架构没有这个缺点。反向代理位于外部不受信任的客户端和内部微服务的后端集合之间,described here by Nordic APIs。客户端从授权服务器获取不透明令牌,并使用该令牌与服务器应用程序通信以处理所有请求。对于每个请求,代理将不透明令牌转换为 JWT 并缓存它们的关联。外部世界从不提供 JWT,从而限制了窃取密钥造成的损害(因为代理转到身份验证服务器以确认不透明的令牌)。但是,这种方法需要取消引用每个客户端令牌,就像会话 ID 需要取消引用每个请求一样,从而消除了 JWT 对客户端请求的好处。在这种情况下,JWT 只允许服务在它们之间传递用户数据,而不必完全信任彼此——但我仍在尝试理解这种方法的价值。
我的担忧似乎只适用于不受信任的客户端使用 JWT 作为身份验证令牌。然而,包括 Google API 在内的许多知名 API 都在使用 JWT。我错过了什么?也许服务器违规很少是只读的?有没有办法降低风险?
【问题讨论】:
-
我想到了一个解决方案,要求攻击者在 RAM 中找到密钥,但显然以服务器必须在每个请求上验证两个签名为代价。集群的每个服务器在启动时都会生成一个公钥/私钥对。它将公钥与 keyID 一起存储在数据库中,但当服务器关闭时,私钥会消失。每个 JWT 都使用集群范围的机密(以防止 DoS 攻击攻击数据库)和 JWT 通过 keyID 标识的密钥进行签名。服务器缓存 keyID 和关联的公钥。不过,我不确定将曝光转移到 RAM 有多大帮助。
-
服务器对每个请求的电子签名验证有什么问题?你应该这样做。它是一个 RSA-HMAC 签名,简单且验证速度非常快。如果密钥被盗,它会发出另一个。如果您担心密钥被盗,请使用硬件令牌 (HSM)
-
取决于你所说的“验证”,我想。您的意思是服务器应该“为每个请求”验证令牌签名吗?如果这就是您的意思,但密钥已被无意中窃取,则签名将正确验证即使是伪造的令牌。这就是我要提出的观点。更有可能的是,我不明白你的意思。我的前提是没有人知道钥匙被偷了。这比没有人知道密码和会话 ID 哈希被盗要糟糕得多。
-
好吧,如果密钥被无意中窃取了,那你的问题就很严重了。但我认为智威汤逊值得。 1) 缓解:定期更换密钥。 2) 避免:使用加密硬件 (HSM) 来存储密钥。它足够便宜 3)预防:审核您的网络基础设施 4)减少影响:它根据用户组或访问区域使用不同的密钥
-
标记并要求模组迁移到security.stackexchange.com - 你可能会在那里得到答案。
标签: security digital-signature jwt secret-key