在JWT Payload中存储敏感数据是否安全?

sk8*_* ツ 8 php jwt

我目前正在学习使用PHP的JWT实现,并希望使用JWT令牌代替我的RESTful应用程序的会话.

在签名创建期间,我正在做这样的事情

token = base64Header + '.' + base64Payload + '.' + signature  
Run Code Online (Sandbox Code Playgroud)

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

我的问题,

  1. JWT仅用于在发送数据时验证服务器的签名吗?
  2. 在Payload中保留敏感数据是不安全的吗?
  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
Run Code Online (Sandbox Code Playgroud)

dav*_*mey 11

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

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

理想情况下,你应该敏感数据存储在有效载荷,因为载荷仅仅是base64编码和加密.这意味着获得令牌的任何人都可以通过简单的base64解码来查看有效负载的内容.

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

保持JWT轻量级.存储用户ID,他们的角色/资助与系统.如果您觉得必须向有效负载添加敏感数据,请尝试重新考虑您的解决方案.


Flo*_*lli 6

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

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

  1. 将敏感数据保存在 Payload 中不安全吗?

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

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

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


Vah*_*afi 5

据我了解,您正在尝试拥有一个完整的stateless服务器,因此您甚至希望在令牌中存储敏感数据。

但是您的服务器不能完全无状态。因为对于注销功能,您必须有黑名单白名单才能使令牌无效。所以在每个请求中你必须接触数据库。如果您没有black listwhite list,即使用户注销,令牌仍然有效。

因此,最好从数据库中获取敏感数据,因为您应该根据每个请求访问您的数据库。

  • 拥有一个没有 `exp` 的令牌是一种非常糟糕的做法。最好有一个 auth 令牌和一个刷新令牌(这是大多数谷歌产品的工作方式)。auth 令牌随每个请求一起发送以授权请求,但仅在短时间内有效(例如 30 分钟)。刷新令牌用于在过期后获取新的身份验证令牌。刷新令牌应该仍然有一个过期时间,但它可以更长(比如 2 周)并且可以自行刷新。要注销,让客户端删除两个令牌。这允许您让用户始终安全登录(只需将新令牌保密) (11认同)
  • 正如您所说的,拥有黑名单或白名单使其比无国籍人少。所以应该避免。最好只有短暂的令牌,所以没有“注销”操作。注销操作只是客户端删除令牌。 (3认同)