如何安全地存储和处理 JWT 的密钥

Posted

技术标签:

【中文标题】如何安全地存储和处理 JWT 的密钥【英文标题】:How to safely store & process secret key for JWT 【发布时间】:2016-10-24 15:31:01 【问题描述】:

阅读本文后:JWT: What's a good secret key, and how to store it in an Node.js/Express app?,关于如何存储“密钥”以分配 JWT 令牌。我有安全问题。我的数据(消息、用户名等)将被加密(在数据库中),只有授权用户才能解密(基于他们的私钥)。由于 JWT 令牌是使用存储在服务器上的 1 个“密钥”生成的,以防攻击者获得“密钥”并控制数据库 - 可以伪造令牌,因此可以绕过“密码”解密数据,这使得加密毫无意义。为了保护“密钥”,我可以使用这些方法

方法一

将“密钥”存储在单独的服务器(如 HSM)上,该服务器将在登录期间接收,然后用于设置令牌

方法二

为每个用户加密某种盐并将其用作“密钥”


我想听听您的想法和想法。脸书或推特是如何做到的?我真的需要 HSM 来存储用于加密的私钥还是有某种替代方案(例如:安全文件系统)?

【问题讨论】:

【参考方案1】:

取决于您的风险偏好。您使用 JWT 的事实表明您的系统不是一个高安全性系统(JWT 不能很容易地在服务器端撤销,因此不适合高度安全的应用程序)。

HSM 是一个不错的选择,尽管您需要将其缓存在内存中以验证每个后续页面请求,除非您使用的是 RSA 算法。

鉴于外部攻击者无法任意访问存储在您服务器上的文件,文件系统可能“足够安全”。

拥有每个用户的密钥在某种程度上违背了拥有客户端会话状态机制的目标,因为您必须在数据库中的每个请求上查找此密钥。

另见Are JWTs a secure option for user authentication?

还有this question。

【讨论】:

您能否解释一下:尽管您需要将其缓存在内存中以验证每个后续页面请求,除非您使用 RSA 算法 - RSA 如何链接到创建还是存储密钥? 如果您使用对称算法对用户进行身份验证(例如 HS256),那么您需要在每个请求上检查 JWT“签名”以对用户进行身份验证。如果您使用的是 RSA,那么私钥可以在 HSM 中,您可以将公钥存储在文件系统中,因为这不敏感,但可以让您验证 JWT 中的签名。 @Rainbow:如果攻击者可以在您的服务器上执行代码,那么这些情况都是一样的。您必须假设,如果攻击者可以执行代码,那么您已经受到威胁。尽管漏洞允许文件访问但不允许代码执行,但它会缓解这种情况。 我正在尝试加密消息,请您回答这个问题:***.com/questions/38013916/… > JWT 不能很容易地在服务器端撤销,因此不适合高度安全的应用程序您能详细说明为什么不这样做吗?这不是重点吗?【参考方案2】:

@SilverlightFox 的答案不正确。

    如果用于签名的 X.509 证书被撤销,JWT 签名验证检查应该会失败(这在jwt.io introduction 页面上有明确描述),因此 JWT 令牌实际上非常适合与公认答案相反的高度安全的应用程序,因此整个答案充其量是有问题的,具有误导性,最坏的情况是非常有害。

    HSM 可以生成安全播种的秘密,因此该秘密在任何情况下都不是确定性的。在 HSM 之外,生成最多的秘密(如果不是全部)只是伪随机的,对于某些加密目的来说不够强大。在 JWT 中,秘密生成器将是读取数据(解密)的一方,因此 HSM 并不意味着这样做,对吧?客户端将需要明文数据而不是 HSM,因此客户端可能会信任 HSM 来创建它的秘密,然后客户端使用该秘密来创建供 JWT 使用的 RSA/ECDSA 私钥对。 IE。 client 创建密钥对。因为只有敏感数据的预期读者才能破译才能获得保证,这意味着客户端必须持有私钥并且绝不与任何其他方共享。客户端将只共享一个公钥,以便其他方可以以只有持有私钥的客户端才能解密的方式加密数据(加密)。共享私钥是一种糟糕的安全做法,会破坏安全模型,使 JWT 毫无意义。 HSM 的替代方案是私有 CA 颁发 X.509 证书以在客户端上生成 RSA/ECDSA 密钥对,但客户端必须再次安全地存储它并将其视为机密。

    文件系统不被认为是安全的,即使是在静态加密的情况下(因为在服务器运行期间没有任何内容是静态加密的,因此服务器不是静态的,在运行期间一切都是明文) .有许多简单的 s-s-rF 和 RCE 漏洞可用于遍历服务器的文件系统,包括已知和未知的,即使是默认安装的软件也经常允许这样做,或者在我们考虑静态代码漏洞之前很容易配置错误。 安全 存储将需要数据保护,即专门构建的安全控制以确保数据受到保护,并且存储在服务器上的纯文本文件没有此类安全特征,除非您特别添加它们。一些示例是确保目录所有者与任何接受用户输入的进程不同,敏感文件存储在任何接受用户输入的进程都无法访问的目录中,并且您正在运行像 SELinux 这样的安全模块来强制执行安全专门保护这些数据的政策。

    拥有每个用户的密钥是使用 RSA/ECDSA 的 JWT 的目标。它恰好有一个目的,所以你在这一点上是非常错误的。它的存在只是为了加密应用程序数据,只有拥有私钥的客户端请求者才能访问和解密它。任何其他实现都没有遵循 JWT,并且可能应用了糟糕的 PKI 实践,并且缺乏它旨在应用的 1 安全特性;保密。还有一种 JWT 根本不需要保密,只需要通过使用 HMAC 来实现完整性,并且根本没有加密,你可能会误解 JWT,并将这些不同的 JWT 模式混合在一起形成你现在的理解。

总的来说,这个公认的答案是对 JWT 基本原理的高度误解,并且有危险的安全建议。

回答问题

由于 JWT 令牌是使用存储在服务器上的 1 个“密钥”生成的

这不是你第一次解释你是如何实现 JWT 的,你说

只有授权用户才能解密(基于他们的私钥)

这是什么?

如上所述;在客户端生成 RSA/ECDSA 密钥对并将公钥发送到服务器以对 JWT 进行签名,服务器不应该拥有客户端用来解密(解密)JWT 的私钥(秘密)。

脸书或推特是如何做到的?

他们是 OIDC 流程中的 JWT 生产者,即他们不使用私钥对 JWT 进行签名,而是使用公钥对其进行签名,以便私钥的持有者(OIDC 消费者)可以解密 JWT 的内容智威汤逊。

旁白;你在解决与 facebook 或 twitter 相同的用例吗?您是否向其他第 3 方保证身份?为了让您的消费者信任您验证的身份,您是 JWT 生产者吗?如果是这样,你永远都不应该知道消费者的私钥,你只需要使用提供给你的公钥签署 JWT。

代币可以伪造

JWT 是代表声明的令牌,它声称是授权,但在验证之前它实际上不是授权。因此“索赔”。此外,JWT 伪造是一个奇怪的概念,当使用公钥签署 JWT 内容时,它是“伪造”吗?您可能误解了这里的 JWT 模式。有使用 shred-secret 签名的 JWT产生一个 HMAC 并且生产者和消费者都需要相同的共享密钥来再现两端匹配的 HMAC。这不是使用私钥和公钥进行加密,JWT 有可以使用 HMAc 的变体,并且共享秘密实际上是敏感的,如果暴露可以用来伪造 HMAC,但是如果您使用 HMAC 样式的 JWT 或加密样式的 (RSA/ECDSA) JWT,您提出的问题并不清楚接受的答案假设你正在使用。

进一步的帮助

读者和过去的参与者;上面的答案有很多东西要学,我鼓励你研究更多关于JWT、ECDSA、RSA、HMAC、OWASPkey management、Cryptography storage cheatsheet和SAMM的secrets management。

然后在此社区中针对您遇到的更具体的问题提出更多问题。

【讨论】:

以上是关于如何安全地存储和处理 JWT 的密钥的主要内容,如果未能解决你的问题,请参考以下文章

如何在浏览器中安全地存储 JWT?

如何使用 Next.js 和 Rails 后端安全地存储 JWT?

如何安全地存储和使用客户的 AWS 密钥

如何安全地存储加密密钥?

存储用于编码/解码令牌数据的 JWT 密钥的安全方式

如何在静态网站中安全存储API密钥