使用JWT令牌身份验证时是否真的需要刷新令牌?

时间:2015-08-17 22:08:13

标签: oauth-2.0 jwt http-token-authentication

我正在引用另一个讨论在JWT中使用刷新令牌的SO帖子。

JWT (JSON Web Token) automatic prolongation of expiration

我的应用程序具有非常常见的架构,我的客户端(Web和移动设备)与REST API通信,然后与服务层和数据层进行通信。

enter image description here

我理解JWT令牌身份验证,但我对如何使用刷新令牌感到困惑。

我希望我的JWT身份验证具有以下属性:

  1. JWT令牌有效期为2小时。

  2. 客户端每隔一小时刷新一次令牌。

  3. 如果未刷新用户令牌(用户处于非活动状态且应用未打开)并且过期,则只要他们想要恢复,就需要登录。

  4. 我看到很多人声称使用刷新令牌的概念可以让他们获得更好的体验,但是我没有看到这样做的好处。管理它似乎更加复杂。

    我的问题如下:

    1. 如果我想使用刷新令牌,那么对于该令牌的良好练习而言长期到期仍然是有益的吗?
    2. 如果我要使用刷新令牌,是否会使用userId和/或JWT令牌保留该令牌?
    3. 当我每1小时更新一次令牌时,这是如何工作的?我是否要创建一个接收我的JWT令牌或刷新令牌的端点?这会更新我原始JWT令牌的到期日期,还是创建新令牌?
    4. 鉴于这些细节,是否真的需要刷新令牌?似乎如果用户只是使用JWT令牌来获取新令牌(根据上面的链接),则刷新令牌已过时。

3 个答案:

答案 0 :(得分:35)

让我稍后回答你的问题,然后开始讨论刷新令牌的整个目的。

所以情况是:

用户打开应用程序并提供其登录凭据。现在很可能该应用程序正在与REST后端服务进行交互。 REST是无状态的,实际上并不是一种授权访问API的方法。因此,到目前为止,在讨论中,没有办法检查授权用户是否实际访问API,或者只是一些随机请求通过。

现在为了能够解决这个问题,我们需要一种方法来了解请求来自授权用户。所以,我们所做的是引入一种称为访问令牌的东西。因此,一旦用户成功通过身份验证,他就会获得一个访问令牌。这个令牌应该是一个长且高度随机的令牌(以确保它不会被猜到)。这就是JWT进入画面的地方。现在,您可能/可能不想在JWT令牌中存储任何特定于用户的详细信息。理想情况下,您只想在JWT中存储非常简单,极其非敏感的细节。操作JWT哈希以检索其他用户的详细信息(IDOR等)由JWT(正在使用的库)本身处理。

所以现在我们的授权访问问题已经解决了。

现在我们谈谈一个攻击场景。让我们假设使用以上所有用户,Alice使用该应用程序拥有授权访问令牌,现在她的应用程序可以向所有API发出请求并根据其授权检索数据。

假设 SOMEHOW Alice失去了访问令牌或换了另一种方式,攻击者Bob可以访问Alice的访问令牌。现在Bob尽管未经授权,但实际上可以向Alice授权的所有API发出请求。

我们理所当然地想要这样做。

现在解决这个问题的方法是:

  1. 要么发现有这种事情发生了。
  2. 减少攻击窗口本身。
  3. 仅使用访问令牌,很难实现上述条件1,因为无论是Alice还是Bob,它都是使用相同的授权令牌,因此两个用户的请求无法区分。

    因此我们尝试实现上述2,因此我们为访问令牌的有效性添加了过期,比如访问令牌对于' t' (短暂的)时间。

    它有什么帮助?好吧,即使Bob拥有访问令牌,他也只能使用它直到它有效。一旦到期,他将不得不再次检索它。现在,你可以说他可以像第一次得到它一样得到它。但话说再说没有100%安全!

    上述方法仍存在问题,在某些情况下实际上是不可接受的。当访问令牌到期时,它将要求用户输入他的登录凭证并再次获得授权访问令牌,至少在移动应用的情况下,这是不好的(不可接受的)用户体验。

    解决方案:这是刷新令牌的来源。它也是一个随机不可预测的令牌,它也会首先与访问令牌一起发布给应用程序。此刷新令牌是一个非常长期存在的特殊令牌,它确保一旦访问令牌到期,它就会向服务器请求新的访问令牌,从而无需用户重新输入其登录凭据以检索新的授权访问令牌,一旦现有的访问令牌已过期。

    现在您可能会问,Bob也可以访问刷新令牌,类似于他破坏访问令牌的方式。是。他可以。然而,现在很容易识别出这种情况,这在单独的访问令牌的情况下是不可能的,并采取必要的行动来减少所造成的损害。

    如何?

    对于每个经过身份验证的用户(通常是移动应用程序),会向应用程序发出一对一映射刷新令牌和访问令牌对。因此,在任何给定的时间点,对于单个经过身份验证的用户,将只有一个访问令牌对应于刷新令牌。现在假设如果Bob已经破坏了刷新令牌,他将使用它来生成访问令牌(因为访问令牌是唯一被授权通过API访问资源的东西)。一旦Bob(攻击者)使用新生成的访问令牌发出请求,因为Alice的(真实用户)访问令牌仍然有效,服务器会将此视为异常,因为对于单个刷新令牌,可以一次只能使用一个授权访问令牌。识别异常,服务器将销毁所讨论的刷新令牌,并且与其一起,它的所有相关访问令牌也将被无效。从而防止任何进一步的访问,无论是真正的还是恶意的,都需要资源的任 用户Alice需要再次使用她的凭证进行身份验证并获取有效的刷新和访问令牌。

    当然,您仍然可以争辩说Bob可以再次访问刷新和访问令牌,并重复上面的整个故事,可能会导致真正的客户爱丽丝的DoS,但是再一次没有像100%安全。

    同样作为一个好习惯,刷新令牌也应该有一个到期,虽然很长。

答案 1 :(得分:5)

我相信在这种情况下,您可以单独使用访问令牌 为您的客户提供更轻松的生活,同时保持刷新令牌的安全优势。

这是如何运作的:

  1. 当您的用户使用凭据(用户名/密码)登录时,您将返回一个 短命的JWT。您还可以创建存储的数据库记录:

    • JWT id
    • 用户ID
    • IP地址
    • 用户代理
    • 一个valid标志(默认为TRUE)
    • createdAt
    • updatedAt
  2. 您的客户端在每个请求中提交JWT。只要JWT没有过期, 它可以访问资源。如果JWT过期,则刷新它 在幕后并返回资源和额外的X-JWT标头 与新的JWT。

  3. 当客户端收到带有X-JWT标头的响应时,它会丢弃该标头 旧的JWT并将新的JWT用于未来的请求。

  4. JWT在服务器上的工作方式

    1. 使用JWT id查找匹配的db记录。
    2. 检查valid标志是否仍然为真,否则拒绝。
    3. 您可以选择比较请求IP地址和用户代理 存储的IP地址和用户代理,并决定拒绝某些内容 腥。
    4. 您可以选择检查数据库记录的createdAt或updatedAt字段,以及 如果时间太长,决定不刷新。
    5. 更新数据库记录中的updatedAt字段。
    6. 返回新的JWT(基本上是已过期的JWT的副本,但延长了到期时间)。
    7. 此设计还可让您选择撤消用户的所有令牌(for 例如,如果用户丢失了手机或更新了他的密码。)

      优点:

      • 您的客户永远不必检查过期时间或刷新令牌 请求,只需检查响应中的X-JWT标题。
      • 您可以根据IP地址,用户代理,max-token添加自定义刷新逻辑 年龄,或其组合。
      • 您可以撤消用户的部分或全部令牌。

答案 2 :(得分:0)

  

如果我要使用刷新令牌,那么对于该令牌的良好实践也将长期到期是否仍然有益呢?

刷新令牌是长期有效的,访问令牌是短期有效的。

  

如果我要使用刷新令牌,该令牌是否可以与userId和/或JWT令牌一起保留?

它将作为单独的令牌持久保存在客户端上,与JWT一起保存,而不是在JWT内部保存。 UserID / UID可以存储在JWT令牌本身内部。

  

每1小时更新一次令牌时,该如何工作?我是否要创建一个接受我的JWT令牌或刷新令牌的端点?这会更新我的原始JWT令牌的到期日期,还是创建新的令牌?

是的,您需要一个单独的服务来发行和刷新令牌。它不会更新现有JWT令牌的到期时间。令牌只是base64编码的JSON字段值对。因此,更改数据会更改输出。令牌还具有发行日期,至少在每次新发行(刷新)时都会更改。因此,每个令牌都将是唯一且新颖的。旧令牌会自动过期,因此您需要所有访问令牌都过期,否则它们将永远存在。

此处的另一个答案指出,当您发行新令牌时,旧令牌会被销毁。事实并非如此。令牌无法销毁。实际上,您可以通过不断联系身份验证服务器并使用“刷新令牌”请求新的新鲜令牌来收获数百个令牌。这些访问令牌中的每一个都将一直有效直到到期。因此,到期是当务之急,它应该很短。

  

考虑到这些详细信息,是否真的需要刷新令牌?看来,如果用户只是使用JWT令牌来获取新令牌(通过上面的链接),则刷新令牌已过时。

JWT令牌具有客户要求权。例如,对JWT令牌的is_manager:true声明可能允许访问经理级功能。现在,如果您决定将用户从经理降级为承包商,那将不会立即生效。用户可能仍在使用旧令牌。最终,当过期时,他点击身份验证服务器以刷新其令牌。身份验证服务器会发出没有管理要求的新令牌,并且用户将无法再访问管理功能。这将创建一个窗口,在该窗口中,用户的声明与服务器不同步。这再次说明了为什么访问令牌应该短暂存在,以便经常进行同步。

基本上,您每15分钟更新一次授权检查,而不是在每个单个请求上都进行检查(这是典型的基于会话的身份验证的工作方式)。如果要实时权限而不是每隔15分钟刷新一次,请JWT may not be a good fit