我正在引用另一个讨论在JWT中使用刷新令牌的SO帖子。
JWT (JSON Web Token) automatic prolongation of expiration
我的应用程序具有非常常见的架构,我的客户端(Web和移动设备)与REST API通信,然后与服务层和数据层进行通信。
我理解JWT令牌身份验证,但我对如何使用刷新令牌感到困惑。
我希望我的JWT身份验证具有以下属性:
JWT令牌有效期为2小时。
客户端每隔一小时刷新一次令牌。
如果未刷新用户令牌(用户处于非活动状态且应用未打开)并且过期,则只要他们想要恢复,就需要登录。
我看到很多人声称使用刷新令牌的概念可以让他们获得更好的体验,但是我没有看到这样做的好处。管理它似乎更加复杂。
我的问题如下:
答案 0 :(得分:35)
让我稍后回答你的问题,然后开始讨论刷新令牌的整个目的。
所以情况是:
用户打开应用程序并提供其登录凭据。现在很可能该应用程序正在与REST后端服务进行交互。 REST是无状态的,实际上并不是一种授权访问API的方法。因此,到目前为止,在讨论中,没有办法检查授权用户是否实际访问API,或者只是一些随机请求通过。
现在为了能够解决这个问题,我们需要一种方法来了解请求来自授权用户。所以,我们所做的是引入一种称为访问令牌的东西。因此,一旦用户成功通过身份验证,他就会获得一个访问令牌。这个令牌应该是一个长且高度随机的令牌(以确保它不会被猜到)。这就是JWT进入画面的地方。现在,您可能/可能不想在JWT令牌中存储任何特定于用户的详细信息。理想情况下,您只想在JWT中存储非常简单,极其非敏感的细节。操作JWT哈希以检索其他用户的详细信息(IDOR等)由JWT(正在使用的库)本身处理。
所以现在我们的授权访问问题已经解决了。
现在我们谈谈一个攻击场景。让我们假设使用以上所有用户,Alice使用该应用程序拥有授权访问令牌,现在她的应用程序可以向所有API发出请求并根据其授权检索数据。
假设 SOMEHOW Alice失去了访问令牌或换了另一种方式,攻击者Bob可以访问Alice的访问令牌。现在Bob尽管未经授权,但实际上可以向Alice授权的所有API发出请求。
我们理所当然地想要这样做。
现在解决这个问题的方法是:
仅使用访问令牌,很难实现上述条件1,因为无论是Alice还是Bob,它都是使用相同的授权令牌,因此两个用户的请求无法区分。
因此我们尝试实现上述2,因此我们为访问令牌的有效性添加了过期,比如访问令牌对于' t' (短暂的)时间。
它有什么帮助?好吧,即使Bob拥有访问令牌,他也只能使用它直到它有效。一旦到期,他将不得不再次检索它。现在,你可以说他可以像第一次得到它一样得到它。但话说再说没有100%安全!
上述方法仍存在问题,在某些情况下实际上是不可接受的。当访问令牌到期时,它将要求用户输入他的登录凭证并再次获得授权访问令牌,至少在移动应用的情况下,这是不好的(不可接受的)用户体验。
解决方案:这是刷新令牌的来源。它也是一个随机不可预测的令牌,它也会首先与访问令牌一起发布给应用程序。此刷新令牌是一个非常长期存在的特殊令牌,它确保一旦访问令牌到期,它就会向服务器请求新的访问令牌,从而无需用户重新输入其登录凭据以检索新的授权访问令牌,一旦现有的访问令牌已过期。
现在您可能会问,Bob也可以访问刷新令牌,类似于他破坏访问令牌的方式。是。他可以。然而,现在很容易识别出这种情况,这在单独的访问令牌的情况下是不可能的,并采取必要的行动来减少所造成的损害。
如何?
对于每个经过身份验证的用户(通常是移动应用程序),会向应用程序发出一对一映射刷新令牌和访问令牌对。因此,在任何给定的时间点,对于单个经过身份验证的用户,将只有一个访问令牌对应于刷新令牌。现在假设如果Bob已经破坏了刷新令牌,他将使用它来生成访问令牌(因为访问令牌是唯一被授权通过API访问资源的东西)。一旦Bob(攻击者)使用新生成的访问令牌发出请求,因为Alice的(真实用户)访问令牌仍然有效,服务器会将此视为异常,因为对于单个刷新令牌,可以一次只能使用一个授权访问令牌。识别异常,服务器将销毁所讨论的刷新令牌,并且与其一起,它的所有相关访问令牌也将被无效。从而防止任何进一步的访问,无论是真正的还是恶意的,都需要资源的任 用户Alice需要再次使用她的凭证进行身份验证并获取有效的刷新和访问令牌。
当然,您仍然可以争辩说Bob可以再次访问刷新和访问令牌,并重复上面的整个故事,可能会导致真正的客户爱丽丝的DoS,但是再一次没有像100%安全。
同样作为一个好习惯,刷新令牌也应该有一个到期,虽然很长。
答案 1 :(得分:5)
我相信在这种情况下,您可以单独使用访问令牌 为您的客户提供更轻松的生活,同时保持刷新令牌的安全优势。
这是如何运作的:
当您的用户使用凭据(用户名/密码)登录时,您将返回一个 短命的JWT。您还可以创建存储的数据库记录:
valid
标志(默认为TRUE)您的客户端在每个请求中提交JWT。只要JWT没有过期,
它可以访问资源。如果JWT过期,则刷新它
在幕后并返回资源和额外的X-JWT
标头
与新的JWT。
当客户端收到带有X-JWT
标头的响应时,它会丢弃该标头
旧的JWT并将新的JWT用于未来的请求。
valid
标志是否仍然为真,否则拒绝。updatedAt
字段。此设计还可让您选择撤消用户的所有令牌(for 例如,如果用户丢失了手机或更新了他的密码。)
X-JWT
标题。答案 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。