【问题标题】:Handling JWT expiration and JWT payload update处理 JWT 过期和 JWT 有效负载更新
【发布时间】:2017-02-11 01:32:48
【问题描述】:

我的个人/爱好应用程序有一个基于 Koa 的 Node.js 后端。

我使用 JWT 令牌实现了会话处理。客户端(AngularJS)在成功登录后获取令牌并将令牌存储在某处(目前在sessionStorage,但就这个问题而言,这无关紧要)。

我有两个问题:

  1. 当我需要更新 JWT 代表的用户记录时,例如,用户打开了双因素身份验证 (2FA),所以我要求他提供他的电话号码,我想在用户的记录。目前,在电话号码成功验证后,我调用后端更新用户记录,并使用更新的用户记录创建一个新的 JWT 令牌(我从 JWT 令牌中排除敏感信息,如哈希密​​码,但我想包括客户端使用的电话号码)。当某些凭据发生更改并使用此新令牌更新现有客户端令牌时,是否可以创建新令牌?我是否应该永远不要创建另一个令牌,只创建一个并且仅在成功验证后才创建?然后如何更新令牌中的有效负载?

  2. 我应该如何处理过期的 JWT 令牌?在我看来,我有 3 个(可能的)场景:

2.1。 JWT 的寿命很短,比如 15 分钟。如果后端服务器回复 401 Unauthenticated“无效令牌”(我猜这是koa-jwt 的默认行为),那么我会自动注销我的客户端并要求重新进行身份验证。但我还设置了一个补充中间件,它是后端链中的最后一个,用于重新创建刷新到期的令牌,客户端也会用刷新的令牌替换现有令牌。因此,如果用户处于活动状态并使用应用程序,则每个受保护的 API 调用在成功的情况下都会创建一个新令牌来替换旧令牌。

2.2。 JWT 设置为长期有效,例如 1 周,如果过期,我会选择加入来自客户端的重新身份验证。

2.3。复制https://www.rfc-editor.org/rfc/rfc6749#section-1.5。在成功验证后创建 JWT 令牌时,我们发送一个 access_token 和一个 refresh_token。当 access_token 过期并且服务器以 HTTP 401 'invalid token' (koa-jwt 默认)响应时,客户端将 refresh_token 发送到后端以要求新的 access_token(以及可选的新 refresh_token) .在这种情况下,我不完全了解如何根据旧 access_token 验证 refresh_token 以提供新令牌?或者为什么我们需要一个 refresh_token?

任何关于上层主题(JWT 更新和 JWT 过期)的通用建议都会有所帮助。

【问题讨论】:

  • 为什么不直接使用 cookie?

标签: javascript node.js jwt koa


【解决方案1】:

从底部开始,我会忽略刷新令牌,因为我认为它们不会对您有所帮助。它们通常针对客户端应用程序可以提供比用户浏览器更安全的存储的其他场景 - 考虑原生移动应用程序或服务器端 Web 应用程序。

刷新令牌是长期存在的。这意味着当客户端从服务器获取令牌时,必须安全地存储此令牌以防止潜在攻击者使用它,因此将它们存储在浏览器中是不安全的。

(重点是我的;来源refresh tokens

这意味着选项 2.3 与 2.2 基本相同,这是一个不错的选项。具有长会话持续时间的 Web 应用程序并不少见。如果您的应用程序不是高度敏感,则可以使用长会话来改善用户体验。例如,Django 使用默认两周作为其会话 cookie 的期限。见SESSION_COOKIE_AGE

剩下的选项(2.1),通常被称为滑动会话。会话超时很短,但只要用户在该时间间隔内继续使用应用程序,会话就会自动更新。这可能是最常见的方法,或者至少是我使用最多的方法,所以我有偏见。我唯一要注意的是,滑动会话通常是使用不透明的会话标识符来实现的,将客户端存储为 cookie,然后将实际会话数据存储在服务器上。

您的方法有点不同,因为您有一个存储在浏览器本地存储中的无状态 JWT 令牌(它包含实际的用户数据)。正如您所说,为了更新令牌,您必须生成一个新令牌,因为您必须生成一个新签名。

签名用于验证 JWT 的发件人是否就是它所说的人并确保消息没有被更改。

(重点是我的;来源JSON web tokens

说了这么多,我会考虑以下几点:

  1. 问问自己是否真的需要 JWT,或者存储为 cookie (HTTP Only) 的常规会话标识符是否会简化您的逻辑。
  2. 如果 JWT 是一项要求,例如,您有另一个 API 也接受这些令牌作为身份验证,那么我会考虑不建议将选项 2.1 或 2.2 作为基于浏览器的应用程序的刷新令牌。

话虽如此,您还应该考虑到 JWT 并不大,但如果您决定自动续订,它们仍然会是开销。您可以通过选择 20 分钟的会话持续时间来稍微缓解这种情况,并且仅在会话结束一半后执行自动续订。

另一点是,应用程序中的 XSS 等漏洞会将访问令牌暴露给攻击者,因为注入的脚本将能够从 localStorage/sessionStorage 读取,这可能是仅支持 HTTP 的另一点会话 cookie 存储。

【讨论】:

    【解决方案2】:

    我想先回答你的第二个问题,然后才能开始回答第一个问题。

    基本上,您提到的第三个选项是更新访问令牌的最佳方式。访问令牌应该是短暂的(~5 分钟),刷新令牌的寿命更长。当您的访问令牌过期时,将您的刷新令牌发送到后端并获取新的访问令牌。所以你的回复应该是这样的:

    {
    "token_type":"bearer",
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
    "expires_in":10,
    "refresh_token":"7fd15938c823cf58e78019bea2af142f9449696b"
    }
    

    所以想法是将您的应用程序分离为授权服务器(生成访问令牌/刷新令牌)和资源服务器(验证访问令牌并访问资源)。您可以维护一个模式来根据授权服务器中的访问令牌验证刷新令牌。请参阅此链接中提到的架构部分,这可能会给您一些想法。 Oauth2。您可以根据需要修改架构。您无需为每个请求调用发送刷新令牌和访问令牌。刷新令牌只能发送到授权服务器以生成新的访问令牌。如何生成刷新令牌?如果我使用 Java,我会使用 UUID.randomUUID() 来生成唯一的刷新令牌。

    现在回答您的第一个问题,如果您想根据更新的用户记录更新您的 JWT 有效负载,那么您可以使用相同的刷新令牌来生成具有更新后有效负载的新访问令牌。逻辑保持不变,因为如果用户记录中存在电话号码,它将被添加到有效负载中,如果不存在,它将在有效负载中为空。

    使用刷新令牌的主要优点是可以使用刷新令牌随时更新访问令牌

    【讨论】:

      猜你喜欢
      • 2016-05-29
      • 2018-12-07
      • 2018-12-19
      • 2016-03-12
      • 2021-12-24
      • 2019-01-16
      • 2022-01-04
      • 2020-03-24
      • 2020-08-26
      相关资源
      最近更新 更多