oauth2.0 使用JWT令牌身份验证时,刷新令牌真的有必要吗?

bis0qfac  于 12个月前  发布在  其他
关注(0)|答案(4)|浏览(174)

我引用了另一篇讨论在JWT中使用刷新令牌的SO文章。
JWT (JSON Web Token) automatic prolongation of expiration
我有一个具有非常常见架构的应用程序,其中我的客户端(Web和移动的)与REST API通信,然后与服务层和数据层通信。
x1c 0d1x的数据
我理解JWT令牌身份验证,但我对如何使用刷新令牌有点困惑。
我希望我的JWT身份验证具有以下属性:

  1. JWT Token的有效期为2小时。
    1.客户端每小时刷新令牌。
    1.如果用户令牌未刷新(用户处于非活动状态且应用未打开)且已过期,则他们需要在想要恢复时登录。
    我看到很多人声称使用刷新令牌的概念可以使这成为一种更好的体验,然而,我看不到这样做的好处。这似乎是管理它的额外复杂性。
    我的问题如下:
    1.如果我要使用刷新令牌,那么对于该令牌的良好实践来说,长期过期不是也很有益吗?
    1.如果我要使用刷新令牌,该令牌是否会与userId和/或JWT令牌一起持久化?
    1.当我每1小时更新一次令牌时,这是如何工作的?我是否要创建一个接受我的JWT令牌或刷新令牌的端点?这会更新我原始JWT令牌的到期日期,还是创建一个新令牌?
    1.如果用户只是使用JWT令牌来获取新令牌(根据上面的链接),那么刷新令牌就过时了。
7nbnzgx9

7nbnzgx91#

让我稍后再回答您的问题,并从实际讨论刷新令牌的整个用途开始。

所以情况是:

用户打开应用程序并提供登录凭据。现在,应用程序很可能正在与REST后端服务交互。REST是无状态的,没有一种方法可以授权访问API。因此,到目前为止,在讨论中,没有办法检查是否授权用户正在访问API,或者只是一些随机请求。
现在为了解决这个问题,我们需要一种方法来知道请求是来自授权用户的。所以,我们所做的就是引入一种叫做访问令牌的东西。所以现在一旦用户成功通过身份验证,他被发给一个访问令牌。这个令牌应该是一个长的和高度随机的令牌(以确保它不能被猜到)。这就是JWT进入画面的地方。现在你可能/可能不想在JWT令牌中存储任何用户特定的细节。理想情况下,你只想存储非常简单的,JWT中的非敏感细节。操作JWT哈希以检索其他用户的细节(IDOR等)由JWT(正在使用的库)本身负责。
所以,现在,我们的授权访问问题已经解决了。
现在我们来讨论一个攻击场景。假设使用上述所有用户Alice,使用应用程序,拥有授权的访问令牌,现在她的应用程序可以向所有API发出请求,并根据她的授权检索数据。
假设SOMEHOWAlice丢失了访问令牌,或者换句话说,一个对手Bob获得了Alice的访问令牌。现在,Bob尽管未经授权,但可以向Alice授权的所有API发出请求。
一些我们不想要的东西。
现在这个问题的解决方案是:
1.或者发现有这种事情发生。
1.减少攻击窗口。
仅使用访问令牌,很难实现上述条件1,因为无论是Alice还是Bob,都使用相同的授权令牌,因此来自两个用户的请求是不可区分的。
因此,我们尝试实现上面的2,因此我们为访问令牌的有效性添加了一个过期时间,假设访问令牌在't'(短暂)时间内有效。
有什么用?好吧,即使Bob有访问令牌,他也只能在它有效的时候使用它。一旦它过期,他将不得不再次取回它。现在,当然,你可以说他可以像第一次那样获得它。但是话又说回来,没有什么比100%安全更好的了!
当访问令牌到期时,它将要求用户输入他的登录凭证并再次获得授权的访问令牌,这至少在移动的应用的情况下是糟糕的(不可接受的)用户体验。

**解决方案:**这就是刷新令牌的用武之地。刷新令牌也是一种随机的不可预测令牌,它也是沿着首先发放给应用的访问令牌。刷新令牌是一种非常长寿的特殊令牌,它确保访问令牌一过期,它就会向服务器请求新的访问令牌,从而消除了用户在现有访问令牌过期后重新输入登录凭据以检索新的授权访问令牌的需要。

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

怎么做

对于每个经过身份验证的用户(通常在移动的应用的情况下),一对一Map的刷新令牌和访问令牌对被发布到应用。因此,在任何给定的时间点,对于单个认证的用户,将只有一个访问令牌对应于刷新令牌。现在假设如果Bob已经泄露了刷新令牌,他会用它来生成一个访问令牌(因为访问令牌是唯一被授权通过API访问资源的东西)。(攻击者)使用新生成的访问令牌请求,因为Alice的(真正的用户)访问令牌仍然有效,服务器会将其视为异常,因为对于单个刷新令牌,一次只能有一个授权的访问令牌。识别出异常,服务器将销毁有问题的刷新令牌,并且沿着,它的关联访问令牌也将失效。从而防止对任何需要授权的资源的任何进一步访问,无论是真正的还是恶意的。用户Alice将被要求再次使用她的凭证进行身份验证,并获取一对有效的刷新和访问令牌。

当然,您仍然可以争辩说,Bob可以再次访问刷新和访问令牌,并重复上面的整个故事,这可能会导致Alice(实际的真正客户)的拒绝服务,但话又说回来,没有什么比100%安全更好的了。
同样作为一个好的实践,刷新令牌应该有一个到期日,尽管是一个相当长的到期日。

t98cgbkg

t98cgbkg2#

我相信对于这种情况,您可以单独使用访问令牌,使客户端的工作更轻松,但保留刷新令牌的安全性优势。
它是这样工作的:

  • 当你的用户使用凭据(用户名/密码)登录时,你会返回一个短暂的JWT。你还创建了一个db记录,在其中存储:
  • JWT ID
  • 用户id
  • IP地址
  • 用户代理
  • valid标志(默认为TRUE)
  • createdAt
  • 更新于
  • 您的客户端在每个请求中提交JWT。只要JWT没有过期,它就可以访问资源。如果JWT过期,您可以在后台刷新它,并返回资源和新JWT的附加X-JWT头。
  • 当客户端收到一个带有X-JWT头的响应时,它会丢弃旧的JWT,并将新的JWT用于未来的请求。

JWT在服务器端的刷新方式

1.使用JWT id查找匹配的db记录。
1.检查valid标志是否仍然为真,否则拒绝。
1.或者,您可以将请求IP地址和用户代理与存储的IP地址和用户代理进行比较,如果有可疑之处,则决定拒绝。
1.或者,您可以检查数据库记录的createdAt或updatedAt字段,并决定是否在时间过长时进行刷新。
1.更新db记录中的updatedAt字段。
1.返回新的JWT(基本上是过期JWT的副本,但过期时间延长了)。
这种设计还将为您提供给予撤销用户所有令牌的选项(例如,如果用户丢失了手机或更新了密码)。

好处:

  • 您的客户端永远不必检查过期时间或刷新令牌请求,它所做的只是检查响应的X-JWT标头。
  • 您可以基于IP地址、用户代理、最大令牌寿命或这些的组合添加自定义刷新逻辑。
  • 您可以撤销用户的部分或全部令牌。
k3fezbri

k3fezbri3#

如果我要使用刷新令牌,那么对于该令牌的良好实践来说,长期过期不是也很有益吗?
刷新令牌是长期的,访问令牌是短期的。
如果我要使用刷新令牌,该令牌是否会与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

hec6srdp

hec6srdp4#

视情况而定

剖析JWT

  • 应包含非敏感信息
  • 应该有一个时间跨度
  • 应该有一个唯一的密钥

NOTE关于JWT,您需要始终记住的一件事是,在安全性、便利性和性能之间总是存在权衡(在某些情况下可以忽略不计)。

Stateful(安全)vs Stateless(方便和性能)

状态令牌

您希望维护令牌的状态,以防令牌泄漏或落入坏人之手。有不同的希望保持令牌的状态。

*白色名单:将令牌id jwt.kid存储在数据库或缓存系统中,如Redismemcached,并设置自动回收时间。每次收到请求时,您都要验证令牌,然后检查存储中是否有相应的jwt.kid值。如果没有找到,拒绝请求。这使您可以更好地控制令牌。您可以随时通过从存储中删除令牌来撤销令牌。但正如您所看到的,您可能会在每次请求时访问您的存储时产生开销。
*黑名单:将token id,s永久保存在某个持久存储中,如果在那里找到token id,则拒绝该token。

无状态令牌

不维护任何状态意味着任何拥有令牌的人都可以发出经过身份验证的请求。您无法撤销无状态令牌。您唯一的希望是时间到期。

鉴权流程

Single Token:访问令牌

根据使用情况,可以是长期的或短期的。一旦过期或被撤销,就需要使用凭据进行身份验证。

多令牌:访问和刷新令牌

结合访问令牌和额外令牌,这种组合确实是为了用户体验。这里发生的是访问令牌是短暂的,可以用于执行各种请求。刷新令牌仅在访问令牌过期后有效,时间约束防止刷新令牌的使用潜在地破坏对应的访问令牌刷新令牌不能用于做除了请求新的访问令牌之外的任何其他事情,这又返回新的访问+刷新令牌对,有效地停用做出请求的刷新令牌。
因此,即使两个令牌都泄露了,也只有访问令牌被认为是有效的,直到它被撤销或过期。刷新令牌只有在访问令牌自然过期并在其使用期限内才有效。

相关问题