对已签名的 JWT 进行加密是否可以保护索赔有效负载?

信息安全 加密 验证 令牌 jwt
2021-09-04 10:50:11

我正在开发服务器-客户端 Web 应用程序,作为身份验证方案,我正在发布 base64 编码的json web tokens考虑以下令牌...

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

解码成这样...

{
  "alg": "HS256",        // header
  "typ": "JWT"
},
{
  "sub": "1234567890",   // payload
  "name": "John Doe",
  "admin": true
},
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), 'secret') // signature 

我关心的是payload这个令牌的一部分,我希望在其中提供定义的声明,例如"role": "readonly". 我担心这些值一旦发布就会被最终用户看到和篡改。修改这部分不会使签名检查无效。我不希望在服务器上保留任何数据以重新检查/比较颁发的令牌 - 我希望保持服务器完全无状态

我想也许可以签署令牌,通过 AES 256 对其进行加密,并将其用作我的“令牌”。流程将被总结为......

  1. 生成并签署 base64 编码的令牌
  2. 通过 AES 256 加密令牌服务器端
  3. 向客户端颁发加密令牌


  4. 收到请求,提供加密令牌

  5. 解密令牌服务器端
  6. 验证 base64 编码的原始令牌签名(现在能够确保声明未被更改)

我的想法是,不会看到声明(有效负载),并且任何篡改此加密值的行为显然都不会像预期的服务器端那样解密。我的问题是——这可行吗?我在网上找不到太多用于加密整个令牌的信息。有没有更好的方法

1个回答

我相信你在问两个问题:

  1. 是否更改有效负载使签名无效:TL;DR:是
  2. 在 JWT 上添加加密是否会给您内容的真实性:TL;DR:不要加密自己,使用 JWE!

以下是更详细的答案:

(1)根据规范, https://www.rfc-editor.org/rfc/rfc7515.txt

签名 JWT (JWS) 的签名是通过受保护的标头和有效负载计算的:

(参见第 5.1 节。消息签名或 MAC 计算)

Compute the JWS Signature in the manner defined for the
       particular algorithm being used over the JWS Signing Input
       ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' ||
       BASE64URL(JWS Payload)). 

因此,更改有效负载应该使签名无效。

(2) 不要加密自己的 JWT!!有一个实际的规范定义了如何加密 JWT(称为 JWE): https ://www.rfc-editor.org/rfc/rfc7516.txt

JWE 使用经过身份验证的加密,这意味着首先对明文进行加密,然后对密文进行完整性检查。您可以从上述规范的第 5.1 节中获得有关明文外观的更多信息。

如果您使用加密或签名格式,则可以将访问策略安全地存储在 JWT 的负载中。如果您不希望客户端或其他方了解策略数据,您可能希望使用加密。如果您不关心谁可以阅读它并且您只关心谁可以更改值,请仅使用签名。

请记住,尽管您添加的安全性越多,对性能的影响就越大,因此请根据您的判断来判断需要什么。

最后说明:签名和加密密钥的密钥管理也成为您需要考虑的一个重要问题,因为最终,有权访问密钥的任何人都可以解密您的 JWE 或修改您的 JWS 的签名。因此,请确保在存储实际密钥的位置、谁可以访问它们以及如何使用它们以及如何将它们保存在内存中时使用良好的安全实践。