我应该以 jwt 还是纯 json 从服务器发送敏感信息?

Posted

技术标签:

【中文标题】我应该以 jwt 还是纯 json 从服务器发送敏感信息?【英文标题】:Should I send sensitive info from the server in a jwt or plain json? 【发布时间】:2021-06-25 07:37:45 【问题描述】:

我有一个返回的登录路径:

带有 jwt 负载的 cookie:user.id 和 user.locale 带有用户对象的 json 响应。

此用户对象包含敏感信息,例如地理位置、电子邮件等。此响应存储在 react 全局状态中并由浏览器缓存。它永远不会暴露在本地/会话存储中。

在将用户对象发送到客户端之前,我是否需要在 jwt 中加密用户对象?还是根本没有区别,用纯json发送就够了?

代码如下所示:

const token = AuthControler.generateToken(user);
const encryptedUser = AuthControler.encryptUser(user);
    return res
      .status(200)
      .cookie("myapp", token, 
        expires: new Date(Date.now() + msPerDay * 14),
        httpOnly: true,
        secure: true
      )
      .json( user: encryptedUser );

【问题讨论】:

没有区别。如下所述,JWT 并没有真正“加密”数据并且不安全。相反,请确保您仅使用 HTTPS 连接 - 这将真正加密通过服务器和客户端之间的线路发送的所有数据。如果您需要将数据保存在客户端但对它不透明(即客户端无法解密数据),那么您将在传输之前由服务器单独安全地加密该数据。如果您需要数据安全客户端可读,只需使用HTTPS。 谢谢。因此,使用 bcrypt 加密令牌并使用 https 连接比使用 jwt 更好。但是,如果可以使用加密库和 http-only cookie 实现适当的安全级别,那么 jwt 的目的是什么? JWT 让人们确信其中的内容是有效的、未更改的以及他们所说的来自谁。这是因为它们是加密的签名,这与加密不同。一个常见的用例是服务器在使用授权令牌登录时提供 JWT。用户/客户端无法更改 JWT 的内容,因为如果他们这样做了,加密签名将不再有效。这使服务器更加确信带有 JWT 的请求来自有效的授权用户。 jwt.io/introduction 【参考方案1】:

即使没有签名私钥/签名秘密,JSON Web 令牌也可以被解码 - 它本身不是加密的。请参阅此处:https://jwt.io/ - 粘贴您的 JWT(已阅读有关敏感数据的警告)并取回用户信息。

如果您想避免将数据暴露给用户,请自己加密它(不是 JWT)。 This technique is often applied to cookies, as well - 例如以防止通过 cookie 和其他篡改进行模糊测试。或者,如果您确实在后端维护某种会话状态,那么它是放置数据的好地方,而不必首先将其发送给客户端。

最后但并非最不重要的一点是,在着手实施安全之前,您必须拥有一个威胁模型。受保护的数据是什么?你在保护谁?是例如“同一台计算机的另一个用户”模型的一部分?是否可以通过其他方式获得数据,例如通过主动向您的系统发出请求?它是否以任何方式受到 GDPR 的影响,如果是,它是否实现了数据处理的最小化?

【讨论】:

我不在后端维护任何会话。我只有一个 http-only cookie,它会在 14 天后自行销毁,用于访问任何敏感路由。好的,所以与其使用 jwt,不如使用 bcrypt.hashSync() 加密 cookie 有效负载,将其作为 http-only 发送,这样任何人都无法获取和篡改它,并使用 bcrypt.compareSync() 在我的身份验证中间件中检查其有效性( )。但是,如果我可以使用加密库和仅 http 的 cookie 实现适当的身份验证,那么 jwt 的目的是什么?我没有发现任何具体的威胁。我只想要一个良好的安全级别。 @DoneDeal0 没有什么能阻止您使用 JWT + cookie 加密,并在 JWT 中存储辅助数据,帮助您的服务识别用户、向他们打招呼(你好,戴夫!)、向他们发送通知等. 这样,您可以同时提供授权和添加上下文,您不必担心将 second 值与令牌一起传递。这是否提供“良好的安全级别”将完全取决于您的威胁模型——在某些时候,您必须做安全作业;应用“最佳实践”是不够的。【参考方案2】:

与流行的看法相反,JWT 令牌可能以 JWS(仅签名)或 JWE(真正加密)格式出现。 JWE 并不是大多数 JWT/JOSE 库的普遍功能。

如果您的系统既是这些令牌的发行者又是消费者,那么您可以使用加密的 JWT,例如使用jose的包EncryptJWT module。

alg: 'dir', enc: 'A256GCM' 适合这样的设置,密钥是 256 位随机密钥。其他 enc 值可能需要不同大小的密钥。

生成的 JWT 看起来像这样,解密之前唯一可读的部分是 JWE 保护标头。

eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..dHrDXdmJIg9pwujk.ZX69BYgPmnCYpztL9BgdyaElv1wEebfq6dIrhoh6TEFiocGK4uwK6rt6pA6oXEkLd-pVVxtIaSTb6r5On1PU0EG9uqJbk7yGaMkq_OF1ZsbVbsHoGPaggoi5j7PCSLmRJdr1iByp7IJ2yWzTx-yzVgnBJgk.dSsVWFbQYLmr0mUBJVWpfQ

【讨论】:

bcrypt 和 jose/jwt/encrypt 之间最安全的选项是什么?另外,在服务器上哪一个是最快的破译?确实,我需要检查每个 api 调用的数据,所以它必须非常快才能获得最佳的用户体验。 我看到上面的解决方案是使用 bcrypt 对 cookie 进行签名。不要对自己这样做,bcrypt 用于单向哈希密码,因此它们真的很难重新计算。它对你的 CPU 来说非常沉重。对于简单的 cookie 签名方案,您可以使用 npmjs.com/package/keygrip 否则 JWE dir+A256GCM 加密是一种快速的 AEAD 密码。但我会留给你检查,我的意思是,将它与 bcrypt 进行比较,你会看到。

以上是关于我应该以 jwt 还是纯 json 从服务器发送敏感信息?的主要内容,如果未能解决你的问题,请参考以下文章

Java - 从请求 JSON 生成 JWS/JWT

从服务器向客户端发送 JSON 格式的 HTML 时,我应该转义内容吗?

如何从 expressjs 发送 jwt 令牌以响应应用程序? [关闭]

Angular 6我必须在客户端生成jwt以匹配服务器还是只匹配服务器

深入总结SpringBoot整合JWT,这应该是全网讲的最通俗易懂的了

带有 JWT 响应的登录请求