可以将用户凭据存储在 JWT 中吗

Is it ok to store user credentials in the JWT

是否可以在 JWT 中存储用户凭据(用户名/密码)(因此 sign 它和 verify 稍后生成的令牌)?

heard那个

No, it is not secure to send a password in a JWT. This is because the JWT claims are simply encoded and can easily be decoded by anyone that sees them. It is not secure to store any sensitive information in a JWT that returned to a user

但我不知道为什么 JWT 网站 recommends 使用它进行身份验证然后:

When should you use JSON Web Tokens?

Here are some scenarios where JSON Web Tokens are useful:

Authentication: This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Single Sign On is a feature that widely uses JWT nowadays, because of its small overhead and its ability to be easily used across different domains

您应该仅使用 jwt 来存储您的 API 将使用的令牌。令牌将在成功登录后生成,它可以附加到发送到您的 API 的任何请求,并且只有在令牌有效时才能处理所有请求。

JWT 是认证的结果。例如

  1. 用户将他的凭据(例如 username/password)发送到身份验证服务。它可以是第三方,一个或一个在您的单体或您自己的专用于身份验证的微服务中。
  2. 服务验证 username-password。如果身份验证成功,它 returns 表示用户已经通过身份验证的 JWT,换句话说,他就是声称自己是的人。此 JWT 可能包含没有敏感信息的负载(不要在此处存储密码)。
  3. 用户使用JWT再次向服务商发起请求。如果 JWT 未过期且未损坏(标志仍然有效),则服务可以信任其 JWT。也许这个任务将委托给授权服务。

JWT 令牌里面有什么?

好吧,最简单的 JWT 包含有关标志的信息(我不能在这里详细输入,因为我不是安全专家)允许在使用 JWT 请求时检查标志是否已损坏已收到。

This information can be verified and trusted because it is digitally signed

除此之外,JWT 允许发送负载。

更正式地说,JWT 由以下部分组成:

  • Header: 令牌类型 + 正在使用的哈希算法
  • 有效负载:声明是关于实体(通常是用户)和其他元数据的陈述。
  • 签名:签名用于验证 JWT 的发送者是否真实,并确保消息在传输过程中没有被更改。

例如,如果我使用我的凭据 username:password 为 gabriel:giussi 向身份验证服务发送请求,它将检查这些凭据,如果它们正常,它可以创建以下 JWT:

然后对于每个请求,我将包含我的用户名和服务的编码 JWT

  • 如果 JWT 签名有效,则执行授权(Gabriel 被授权做什么?)。
  • 如果 JWT 已过期,请让我重新登录
  • Return 如果符号被破坏,则验证错误。

简短地说:是的,如果您在将数据放入 JWT 的有效负载之前加密数据并在 JWT 验证后解密以使用它,则可以 pass/receive JWT 中的敏感数据。

  1. 在一般情况下,您不需要在 JWT 中保留用户凭据,因为 JWT 本身就是一个动态生成的凭据,表示在 JWT 第一代时提供的登录名/密码。

    1.1 然而,您可以传递一些不像纯登录名/密码那么敏感的东西,但仍然包含您在 JWT 验证时需要的有价值的信息。它可以是用户 ID(如果需要,在 sub claim, hashed 中),或访问级别代码等。

  2. 不过,如果您愿意,可以使用 JWT 传递敏感信息。这一切都非常简单,如下所示。

    2.1 对于敏感数据,您可以在 JWT 的负载中使用您的特定 private claims,例如:

    {
      // These are registered claims: (see https://www.rfc-editor.org/rfc/rfc7519#section-4.1)
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    
      // There can be some public claims you are not afraid to expose to the world
      // these are omitted here for brevity (see https://www.rfc-editor.org/rfc/rfc7519#section-4.2).
      "omitted": "for brevity",
    
      // And here can go some private claims you wish to include in the payload, e.g.:
      "sensitiveInfo": {
        "username": "admin",
        "password": "12345",
        "account_balance": 10000,
        "etc": "something else"
      }
    }
    

    2.2 默认情况下,sensitiveInfo 有效负载密钥仅采用 base64 编码(因此任何获得 JWT 的人都可以轻松读取)。为了确保它的安全,您可以使用一些外部模块(例如您选择的 crypto or bcrypt on NodeJS or PHP's techniques)对其进行加密。

    2.3 在这种情况下:

    • 在 JWT 生成步骤中,您必须先加密密钥数据,然后再将整个有效负载提供给 JWT 生成器。
    • 在 JWT 验证步骤中,在 JWT 成功通过标准验证后(例如 jsonwebtocken jwt.verify() in Node) you get the decoded payload with encrypted data in sensitiveInfo key. You now just have to decrypt 数据并按计划使用它。

就是这个。