将敏感数据存储在 JWT 有效负载中是否安全?

2022-08-31 00:35:25

我目前正在学习使用PHP实现JWT,并希望使用JWT令牌而不是我的RESTful应用程序的会话。

在签名创建期间,我正在执行类似操作

token = base64Header + '.' + base64Payload + '.' + signature  

在这里,我们只使用base64的有效载荷。如果我粘贴像 https://jwt.io/#debugger 这样的网站,Payload就会被解密(即使签名是错误的)。

我的问题,

  1. JWT 是否仅用于在发送数据时与服务器验证签名?
  2. 将敏感数据保存在有效负载中是否不安全?
  3. 如果不安全,有什么方法可以保护有效负载?

以下是我编写的示例代码

<?php
    $headers = base64_encode(json_encode([
        "typ" => "JWT",
        "alg" => "HS256"
    ]));
    $claims = base64_encode(json_encode([
        "sub" => "1234567890",
        "name" => "John Doe",
        "admin" => true,
        "jti" => "870a3de5-ea7b-4062-abef-11180e530f5a",
        "iat" => 1492603378,
        "exp" => 1492606978
    ]));
    $payload = $headers.".".$claims;
    $signature = base64_encode(hash_hmac("sha256", $payload, 'secret', true));
    $encodedJWT = $payload.".".$signature;
    // eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImp0aSI6Ijg3MGEzZGU1LWVhN2ItNDA2Mi1hYmVmLTExMTgwZTUzMGY1YSIsImlhdCI6MTQ5MjYwMzM3OCwiZXhwIjoxNDkyNjA2OTc4fQ.nvw-bAUgr7H_xr3q8_Yz8rCNtMohtn2YlCmcLoLBWlc

答案 1

如果我粘贴像 https://jwt.io/#debugger 这样的网站,Payload就会被解密(即使签名是错误的)。

第三方无法验证签名,因为他们没有密钥。有效负载不会被解密 - 它会被解码。

理想情况下,您不应将敏感数据存储在有效负载中,因为有效负载仅经过 base64 编码,未加密。这意味着任何获得令牌的人都可以通过简单地对base64解码来查看有效负载的内容。

如果您在Web浏览器的本地存储中有一个令牌,并且您的网站存在XSS漏洞,则窃取令牌变得微不足道。攻击者有一个有效的JWT(无论如何都希望很快就会过期),这已经够糟糕的了,但是如果它包含敏感数据,那么你就有真正的麻烦了。想象一下,由于潜在的大规模妥协,他们必须通知您网站上的所有用户,他们现在必须更改有关自己的各种敏感数据。

保持智威汤逊的轻量级。存储系统中存储用户 ID、其角色/授权。如果您觉得必须将敏感数据添加到有效负载中,请尝试并重新考虑您的解决方案。


答案 2
  1. JWT 是否仅用于在发送数据时与服务器验证签名?

不,不仅有签名的 JWT (JWS - RFC 7515),还有加密的 JWT (JWE - RFC 7516)。

  1. 将敏感数据保存在有效负载中是否不安全?

加密 JWT 后,可以安全地共享敏感数据(除非算法或密钥泄露)。

但是在你的例子中,我没有看到任何敏感数据,因此我想知道在你的情况下使用JWE是否真的重要。我强烈建议您阅读这篇关于JWT和会话的博客文章,以及为什么您不应该将它们用于此目的(也请看一下该部分2)。

如果你真的想使用JWE,那么我写了一个PHP库,它已经能够加载和创建任何类型的Jose(JWS / JWE),并且支持RFC 7518的几乎所有算法。可能存在其他库,但没有引用列表(https://jwt.io/ 仅列出 JWS 实现)。


推荐