刷新令牌有什么意义?

94

我必须承认,这个问题我一直持有很长时间,但从未真正理解。

假设授权令牌就像一个保险柜的钥匙,当它过期后就无法再使用。现在我们得到了一个神奇的刷新令牌,可以用它来获取另一个可用的钥匙,然后继续下去...直到神奇令牌过期。那么为什么不将授权令牌的过期时间与刷新令牌设置为相同呢?根本没有必要吗?

这是什么原因呢?是历史原因吗?


4
OAuth 2.0为什么有访问令牌和刷新令牌两种令牌?OAuth 2.0使用访问令牌来授权API请求。当用户通过身份验证向客户端授权后,客户端将使用访问令牌向受保护资源发出请求。然而,访问令牌有时可能会过期或被撤销,这会导致客户端无法访问受保护的资源。在这种情况下,客户端需要使用刷新令牌来获取新的访问令牌,而无需再次要求用户进行身份验证。因此,访问令牌和刷新令牌一起使用,以确保应用程序可以持续地访问受保护的资源,同时也确保用户的安全性和隐私性。 - Anders Lindahl
刷新令牌并不是关于更新用户角色或撤销访问权限,也不是仅在第一次请求用户/密码时使用。你可以只用访问令牌就实现所有这些。它主要是为了减少攻击面。更多信息请参见此处 - mfaani
11年过去了,这个问题仍然如此相关!在阅读了所有的答案之后,我终于明白了。明年再见,当我又忘记的时候。 - Steve
11年过去了,这个问题仍然如此贴切!在阅读了所有的回答后,我终于明白了。明年再见,当我再次忘记的时候。 - undefined
5个回答

59

我最近阅读了Taiseer Joudeh的一篇文章,发现它非常有用,他说:

在我看来,使用刷新令牌有三个主要好处,它们是:

  1. 更新访问令牌内容:你知道访问令牌是自包含的令牌,一旦生成,它们包含有关已认证用户的所有权利声明(信息)。现在,如果我们为名为“Alex”的用户颁发了一个长期有效的令牌(例如一个月时间)并将其注册为“用户”角色,则此信息被包含在授权服务器生成的令牌中。如果您稍后决定(在他获得令牌后的两天内)将其添加到“管理员”角色,则无法更新令牌中包含的此信息,需要要求他再次进行身份验证,以便授权服务器将此信息添加到新生成的访问令牌中,但在大多数情况下这是不可行的。您可能无法联系到获得长期访问令牌的用户。因此,为解决此问题,我们需要颁发短期有效的访问令牌(例如30分钟),并使用刷新令牌获取新的访问令牌。一旦您获得新的访问令牌,授权服务器将能够为用户“Alex”添加新的声明,将其分配到“管理员”角色中,一旦生成了新的访问令牌。

  2. 撤销已认证用户的访问:一旦用户获得长期有效的访问令牌,只要他的访问令牌没有过期,他就能够访问服务器资源,除非授权服务器实现自定义逻辑(强制您在数据库中存储生成的访问令牌,并在每个请求中进行数据库检查),否则没有标准方式可以撤销访问令牌。但是使用刷新令牌,系统管理员可以通过简单地从数据库中删除刷新令牌标识符来撤销访问权限,因此,一旦系统使用已删除的刷新令牌请求新的访问令牌,授权服务器将拒绝此请求,因为刷新令牌不再可用(我们将更详细地介绍这一点)。

  3. 无需存储或请求用户名和密码:使用刷新令牌允许您在用户第一次进行身份验证后仅一次请求其用户名和密码,然后授权服务器可以发行非常长期的刷新令牌(例如1年),用户将保持登录状态直到系统管理员尝试撤销刷新令牌。您可以将此视为对服务器资源进行离线访问的方法,如果您正在构建一个将由前端应用程序消耗的API,并且频繁要求用户名/密码不可行,那么这将很有用。


4
为什么不使用短暂的访问令牌,在其过期时检查凭据?如果用户仍然有效,则重置访问令牌的到期时间。我不理解为什么需要刷新令牌? - Rick Jolly
"...一旦生成,它们包含有关经过身份验证的用户的所有声明(信息)..." 而我认为将任何与用户相关的信息,即使已加密,放入令牌中都被认为是不良实践。" - bklaric
这要看你所指的用户信息是什么。它说的是“所有索赔信息”,而不是所有用户信息。 - Kiarash
1
@RickJolly:访问令牌通常包含足够的信息来识别用户及其角色,而无需访问数据库。这通常通过签名和加密令牌(例如hmac签名)来实现。在原始内容中添加、删除或更改一个字符将为您提供完全不同的签名令牌。因此,如果在对“userid:alex;role:user;client:foobar.com;ts:1552806134”进行签名和加密后,令牌看起来像'kE4ia6',则对于“userid:alex;role:admin;client:barbaz.net;ts:1552806565”,即使是相同的用户,它也会完全不同。 - Michael Ekoka
1
@RickJolly:另一方面,刷新令牌只是指向单个用户的不透明密钥。每次需要查询数据库以查找它属于谁(性能受损)。实际上,它是用户凭据的混淆表示。因此,您可以将其存储在客户端上而不是存储用户名:密码(最佳做法)。在新项目中,您可以像使用访问令牌一样使用它,但由于前面提到的限制,您可能最终需要更具可扩展性的东西。刷新令牌/访问令牌设置是一个不错的选择。 - Michael Ekoka

35

我想要补充另一种观点。

无状态身份验证,避免每个请求都访问数据库

假设您想要创建一个无状态(无会话)的安全机制,可以对数百万用户进行身份验证,而无需进行数据库调用以进行身份验证。随着应用程序所获得的所有流量,减少每个请求中的数据库调用是很值得的!它需要是无状态的,因此可以轻松地集群和扩展到数百甚至数千台服务器。

在传统的会话中,用户登录后,我们从数据库中读取其用户信息。为了避免不断读取,我们将其存储在会话(通常是内存或某些集群缓存中)。我们将会话ID作为cookie发送给客户端,并附加到所有后续请求中。在后续请求中,我们使用会话ID查找会话,该会话反过来包含用户信息。

直接将用户信息放入访问令牌中

但我们不想使用会话。因此,不要将用户信息存储在会话中,而是将其直接放入访问令牌中。我们对令牌进行签名,以防止任何人篡改它。这样就可以在没有会话且无需为每个请求查找用户信息的情况下进行身份验证。

没有会话...无法封禁用户?

但是,没有会话有一个很大的缺点。例如,如果此用户被封禁怎么办?在旧情景中,我们只需删除他的会话。然后,他必须重新登录,但他将无法这样做。封禁完成。但在新情景中没有会话。那么我们该如何封禁他呢?我们必须(非常礼貌地)要求他删除访问令牌。检查每个传入请求是否在禁令名单中?是的,可以工作,但现在我们又不得不进行我们不想要的数据库调用。

使用短暂的访问令牌来妥协

如果我们认为在被封禁后用户仍然可以使用其帐户 10 分钟是可以接受的,那么我们可以创建一个折中方案——每次请求都检查数据库和只在登录时检查之间的状态。这就是刷新令牌发挥作用的地方。它们允许我们使用短暂的访问令牌的无状态机制。我们无法吊销这些令牌,因为没有对它们进行数据库检查。我们仅根据当前时间检查其到期日期。但一旦它们过期,用户就需要提供刷新令牌才能获得新的访问令牌。此时,我们会检查数据库并查看用户是否已被封禁。因此,我们拒绝了获取访问令牌的请求,并且封禁开始生效。

3
但一旦访问令牌过期,用户将需要提供刷新令牌以获取新的访问令牌。为什么需要一个刷新令牌呢?为什么不基于原始令牌中的凭据重新验证用户,然后如果有效,则重置该令牌的到期日期? - Rick Jolly
2
@RickJolly 因为访问令牌通常不包含凭据(刷新令牌也没有)。其工作方式是令牌由发行方签名。因此,发行方知道这些令牌有效(直到过期为止)。通常,令牌包含用户名以及用户拥有的角色/权限等信息。双方都可以使用令牌来显示此类信息,而无需首先进行数据库/网络调用。 - Stijn de Witt
3
好的,谢谢。但是如果我们忽略我关于根据访问令牌中的凭据重新验证用户的内容(这可能只是检查用户ID是否仍然被允许),我仍然看不出需要刷新令牌的理由。这就是我的问题:“为什么需要刷新令牌?” - Rick Jolly
1
@RickJolly 理解了。我猜协议的设计者们得出结论,最简单的方法是将两个任务分开:为所有操作提供访问令牌并提供刷新令牌以获取访问令牌。这将刷新的责任放在客户端手中,减少了服务器的复杂性。 - Stijn de Witt
这是一个非常好的解释,详细说明了场景。非常感谢! - Zachary Bohn

16

参考答案(via @Anders)很有帮助,它指出:

在发生妥协的情况下,其有效时间很短,但令牌是通过SSL使用的,因此不太可能被攻击者获取。

我认为重要的部分是访问令牌通常会被记录(特别是当作为查询参数使用时,这对于JSONP很有用),因此最好让它们具有短暂的生命周期。

对于服务提供商大规模实现OAuth 2.0,还有另外一些原因:

  1. 如果可以不担心撤销,API服务器可以安全地验证访问令牌而无需进行数据库查找或RPC调用。这可以对API服务器产生强大的性能优势并减少复杂性。最好是允许令牌撤销需要花费30分钟到1小时(或访问令牌的长度)。当然,API服务器也可以保留在内存中列出的最近1小时内吊销的令牌列表。

  2. 由于令牌可以具有多个范围并访问多个不同的API服务,具有短暂的访问令牌可以防止API服务的开发人员获得对API服务B中用户数据的终身访问权限。分区对于安全性是有利的。


谢谢。然而,我认为这两个额外的理由都不够强大。1、对于拥有数百万应用程序的大型网站来说,保留所有访问令牌在内存中是不可能的,DB查找或RPC调用是不可避免的。当然,我没有数据支持我的论点。2、我认为访问令牌的范围与刷新令牌的范围相同,至少在Google的实现中是如此。因此,即使刷新令牌泄漏,也不可能发生跨范围攻击。 - wangii
我认为避免访问令牌被记录下来是一个更好的理由,但只有在站点A被用户B授权从发行者C获取访问信息,并且令牌以某种方式发送给第四方时才有效。对我来说,如果站点A托管在第四方的服务器上,这似乎会发生...但是如果第四方对服务器拥有完全访问权限,那么这仍然是毫无意义的,对吧? - wangii
4
@wangii - Re #1 - 访问令牌可以通过加密或签名进行自我验证,因此不需要进行数据库查找或RPC调用。刷新令牌可以保持不透明,并且在OAuth提供程序中可以撤销。Re #2 - 是的,访问令牌的范围相同。然而,给一个服务(A)的开发人员终身访问用户在服务(B)上的数据比仅在用户活跃使用服务(A)时给他们访问权限要糟糕得多。 - Ryan Boyd
我不太明白。你需要对数据库/会话验证刷新令牌,使其具有状态。此外,您需要在存储之前加密刷新令牌,并检查黑名单,这会导致额外的开销。鉴于短暂的访问令牌,您可能需要经常进行此检查...您能否澄清一下? - html_programmer
@KimGysen抱歉,我不确定您不理解的部分是哪里。刷新令牌确实需要针对数据库或撤销列表进行检查,但是想法是访问令牌将在每次刷新时被多次使用。(即,XX或XXX API请求。 - Ryan Boyd

5

简短的回答:

刷新令牌允许对令牌进行不同形式的作用域和衰减时间设置。实际资源令牌生命周期短暂,而刷新令牌可以保持有效多年(移动应用程序)。这提供了更好的安全性(不需要保护资源令牌)和性能(只有刷新令牌API需要检查DB的有效性)。


2
这对我来说似乎是最清晰和最好的答案...谢谢。 - jess
为什么资源令牌不需要受到保护?是因为它们的生命周期短暂,如果被攻击,风险较小,因为它们很快就会过期吗? - Quinn Comendant
1
@QuinnComendant 没错。更准确地说,资源令牌不那么重要需要保护,因为它们的生命周期较短,但并不意味着它们不需要任何保护。 - B M

3
以下是关于刷新令牌的附加好处。
安全第一!
访问令牌具有短暂性。如果有人窃取了访问令牌,他只能在访问令牌过期之前访问资源。
“...但如果刷新令牌被盗了呢?”
如果攻击者窃取了刷新令牌,他可以获取访问令牌。因此,建议每次获得新的访问令牌时都发放一个新的刷新令牌。如果使用相同的刷新令牌两次,那么很可能意味着刷新令牌已被盗。
当每次使用后刷新令牌更改时,如果授权服务器检测到刷新令牌被使用了两次,这意味着它很可能已经被复制并被攻击者使用,授权服务器可以立即撤销与其相关的所有访问令牌和刷新令牌。
请务必记住,刷新令牌必须尽可能安全地存储。
当然,这只是另一层安全保障。攻击者仍然有时间获取访问令牌,直到刷新令牌第二次使用(无论是由攻击者还是真正的用户使用)。
请始终记住,必须尽可能安全地存储刷新令牌。
来源:https://www.oauth.com/oauth2-servers/making-authenticated-requests/refreshing-an-access-token/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接