为什么OAuth v2同时有访问令牌和刷新令牌?

830

OAuth 2.0协议草案的第4.2节指出,授权服务器可以返回一个access_token(用于认证资源),以及一个refresh_token,后者仅用于创建新的access_token

https://www.rfc-editor.org/rfc/rfc6749#section-4.2

为什么需要两个令牌?为什么不让access_token的有效期与refresh_token相同,而不提供refresh_token呢?

21个回答

6
假设您的access_token非常长时间,且没有refresh_token,那么在一天内,黑客可以获取此access_token并访问所有受保护的资源!
但是,如果您有refresh_token,则access_token的生命周期很短,因此黑客难以攻击您的access_token,因为它将在短时间内失效。只有使用不仅refresh_token还要使用client_idclient_secret才能检索回access_token,而黑客没有这些信息。

2
通过不仅使用refresh_token,还使用client_id和client_secret,黑客无法获得。1.假设只有访问令牌,那么黑客是否仍然需要client_id和client_secret?2.如果黑客是一个好的黑客,那么他也可以破解client_id和client_secret。无论如何,破解其他东西对比较并不重要,因为如果只使用访问令牌,则难以破解,长话短说,您没有比较相同的情况。你把它们混在一起了。 - mfaani

4

关键在于扩展,保持资源服务器无状态。

  • 您的服务器/资源服务器
    • 服务器是无状态的,意味着不会检查任何存储以提供非常快速的响应。通过使用公钥验证令牌的签名来实现此功能。

    • 在每个请求中检查access_token

    • 只需检查access_token的签名和过期日期即可获得响应,这样可以快速响应并允许扩展。

    • access_token应具有短的到期时间(几分钟),因为如果泄露了access_token,则无法撤销它,损害是有限的。

  • 认证服务器/OAuth服务器
    • 服务器不是无状态的,但由于请求要少得多,所以没问题。
    • 仅当access_token过期时才检查refresh_token。(例如每2分钟)
    • 请求速率远低于资源服务器。
    • 将刷新令牌存储在DB中并可撤销。
    • refresh_token可以具有长的到期时间(几周/几个月),如果泄露了,则可以撤销。

然而,有一个重要的注意事项,认证服务器的请求要少得多,因此可以处理负载,但是存储问题可能会成为问题,因为它必须存储所有的refresh_tokens,如果用户急剧增加,这可能会成为问题。


1
但仍然可以使用访问令牌吗?在资源服务器上,只需在访问令牌到期时拒绝用户的访问令牌即可(恶意用户可能不会篡改此过期时间,因为资源服务器具有公钥并且可以检查访问令牌中数据的签名和“诚实性”),一旦拒绝访问令牌,则用户必须将其提供给认证服务器以 延长相同访问令牌的到期时间,如果它尚未被撤销,或者用户没有任何可疑的IP /位置更改等。 - aderchox
@aderchox,是的,正如你描述得非常好的那样,它被用于资源服务器和认证服务器。 - Bernard Wiesner

4
虽然刷新令牌由授权服务器保留,但访问令牌是自包含的,因此资源服务器可以在不存储令牌的情况下验证它,这样可以节省在验证时检索令牌的工作量。 另一个讨论中缺少的要点来自rfc6749#page-55
“例如,授权服务器可以在每次访问令牌刷新响应中使用刷新令牌轮换。旧的刷新令牌被使无效,但由授权服务器保留。如果刷新令牌被攻击者窃取并随后被攻击者和合法客户端使用,则其中之一将呈现已失效的刷新令牌,这将通知授权服务器存在漏洞。”
我认为使用刷新令牌的整个意义在于,即使攻击者以某种方式成功获取了刷新令牌、客户端ID和秘密组合,也可以跟踪从攻击者那里获取新访问令牌的后续调用,以防止每个刷新请求都导致新的访问令牌和刷新令牌。

我认为这是一个非常重要的观点 :-) 它也在某种程度上无效了这里的论点 https://auth0.com/docs/tokens/refresh-token/current#restrictions,即“单页应用程序(通常实现单页登录流程)绝不能在任何情况下获取刷新令牌。原因是这个信息非常敏感。你可以把它看作用户凭据,因为刷新令牌允许用户保持长期认证。因此,你不能在浏览器中存储这些信息,它必须得到安全地存储。” - Simon_Weaver

3
让我们考虑一个系统,每个用户都与一个或多个角色相关联,每个角色都与一个或多个访问权限相关联。为了改善API的性能,可以缓存此信息。但是,用户和角色配置可能会发生更改(例如,可能授予新的访问权或撤销当前访问权),这些更改应反映在缓存中。
我们可以使用访问令牌和刷新令牌来实现此目的。当使用访问令牌调用API时,资源服务器会检查缓存以获取访问权限。如果有任何新的访问授权,则不会立即反映出来。一旦访问令牌过期(例如30分钟),客户端使用刷新令牌生成新的访问令牌时,缓存可以使用来自数据库的更新的用户访问权限信息进行更新。
换句话说,我们可以将使用访问令牌的每个API调用中的昂贵操作移动到使用刷新令牌生成访问令牌的事件中。

2
据我所知,刷新令牌只是为了提高性能和节省成本,如果需要撤销访问权限,则需要使用刷新令牌。
例如1:不要实现刷新令牌;只实现长期有效的访问令牌: 如果用户滥用服务(例如:未支付订阅费),则需要撤销访问令牌=> 您需要在每个需要访问令牌的API调用上检查访问令牌的有效性,这将很慢,因为它需要进行数据库查找(缓存可以帮助,但这更加复杂)。
例如2:实现刷新令牌和短期有效的访问令牌: 如果用户滥用服务(例如:未支付订阅费),则需要撤销访问令牌=> 短期有效的访问令牌将在短时间内过期(例如1小时),用户需要获取新的访问令牌,因此我们不需要在每个需要访问令牌的API调用上进行验证。您只需要在从刷新令牌生成访问令牌时验证用户即可。对于不良用户,如果无法生成访问令牌,您可以注销该用户。当用户尝试重新登录时,验证将再次运行并返回错误。

2
刷新令牌访问令牌只是术语。
以下类比有助于巩固使用访问令牌和刷新令牌的理由:
假设Alice通过邮寄向Bob发送一张支票,从发行之时起可在1小时内兑现(假设时间),否则银行将不予承兑。但Alice还附上了一张便条给银行,要求银行在支票受到轻微延误的情况下接受并兑现支票(在规定范围内)。
Bob收到这张支票时,如果发现被篡改(令牌篡改),他将自行丢弃这张支票。否则,他可以拿着它去银行兑现。在这里,当银行注意到发行时间已经超过1小时的限制时,但看到了Alice的签名便条,并询问Alice是否仍然具有正确的权限时。
银行查看便条后,试图验证签名消息并检查Alice是否仍具有正确的权限。如果是,则银行会兑现支票。Bob现在可以向Alice确认。
尽管不是非常准确,但这个类比可以帮助您注意到处理事务所涉及的不同部分:
  • Alice(发送方-客户端)
  • Bob(接收方-资源服务器)
  • 银行(授权服务器)
  • 验证过程(数据库访问)
  • 支票(访问令牌)
  • 备注(刷新令牌)
主要是为了减少对认证服务器和最终数据库的API调用数量,以优化可伸缩性。我们需要在便利性和安全性之间保持正确的平衡。
注:在链中,响应请求的顺序通常是授权服务器比资源服务器更早。

1
首先,客户端通过提供授权授予与授权服务器进行身份验证。 然后,客户端通过提供访问令牌向资源服务器请求受保护的资源。 资源服务器验证访问令牌并提供受保护的资源。 客户端通过授权访问令牌向资源服务器发出受保护的资源请求,在此过程中,资源服务器验证并服务请求(如果有效)。该步骤一直重复,直到访问令牌过期。 如果访问令牌过期,客户端通过提供刷新令牌向授权服务器进行身份验证并请求新的访问令牌。如果访问令牌无效,资源服务器会向客户端发送无效的令牌错误响应。 客户端通过授权刷新令牌与授权服务器进行身份验证。 然后,授权服务器通过对客户端进行身份验证来验证刷新令牌并发放新的访问令牌(如果有效)。

这实际上并没有提到刷新令牌的来源。我猜第二段应该说“访问令牌+刷新令牌”? - Simon_Weaver

1

由于刷新和访问令牌是充满语义的术语,术语转换可能会有所帮助?

  • 可撤销令牌 - 必须与授权服务器进行检查的令牌
    • 可以链接(参见RTR-刷新令牌轮换)
    • 可用于创建不可撤销令牌,但也可以直接使用(当数量较少且检查不成为负担时)
    • 可以长期存在,但这取决于用户需要多频繁地使用凭据(用户名/密码)来获取新凭据
    • 可以在RTR或任何其他可疑行为上作废
  • 不可撤销令牌 - 自包含且不需要与授权服务器进行检查的令牌
    • 对于大数据、分布式服务器/ API 调用以实现水平扩展非常有用
    • 应该短暂存在(因为不可撤销)

在2020年,越来越多的人接受了刷新令牌也可以存在于浏览器中的事实(最初是针对后端系统提供的)- 请参见https://pragmaticwebsecurity.com/articles/oauthoidc/refresh-token-protection-implications。由于这个原因,重点从“可刷新性”(在没有用户的情况下,后端如何延长对API的访问权限)转向了“可撤销性”。

所以,根据我的看法,将刷新令牌视为可撤销令牌,将访问令牌视为不可撤销令牌(也许是快速到期的不可撤销令牌)更安全些。

作为一个关于良好实践的附注,在2021年,系统总是可以从可撤销令牌开始,并在授权服务器压力增加时转向不可撤销令牌。


1

我这里有一些额外的资源,可以更清楚地解释我们为什么需要刷新令牌。以下是其中一些资源的关键点:

  • 在现实世界中,最好有称为 authServerresourceServer/s 的单独服务器
    • authServer - 仅用于身份验证和授权。该服务器的职责是发出refresh tokenaccess token并且也可以login & logout用户
    • resourceServer - 这个服务器(也可以是多个负载平衡的服务器)提供受保护的数据。例如,在电子商务项目中,这些数据可能是productsreviews
  • refresh_token的一个用途是,我们不必每次需要新的access_token时都将username and password (credentials)通过网络(从前端到authServer)发送。这只需要在第一次(当您还没有refresh_token时)进行,之后refresh_token将从authServer得到新的access_token,因此您可以继续向受保护的resourceServer发出请求。这里的优点是,由于用户不必每次提供凭据,因此用户的用户名和密码不容易被攻击者获得。
  • refresh_token的另一个主要用途是,假设在现实世界中,您的authServerresourceServer更加安全(第三方服务如auth0oktaazure等或您自己的实现)。您将只向resourceServer(以获取数据)发送access_token,而永远不必向resourceServer发送refresh_token。因此,当您将access_token发送到resourceServer时,有可能会有黑客拦截您的resourceServer(因为它不像authServer那样安全),并获得访问您短暂的access_token的权限。
    • 因此,access_token的生命周期很短(例如30分钟)。请记住,当这个access_token过期时,您将向authServer(比resourceServer更加安全)发送refresh_token以获取新的access_token。由于您在任何时候都没有向resourceServer发送refresh_token,所以拦截resourceServer的黑客无法获取您的refresh_token。如果作为开发人员,您仍然怀疑用户的refresh_token可能会被黑客攻击,那么您可以使所有用户logout(使所有用户的refresh_token无效),这样用户将重新登录(提供用户名和密码)以获取新的refresh_token + access_token,从而再次恢复正常。

一些有用的资源

带有和不带有刷新令牌的工作流程 - Youtube

JWT身份验证代码示例 - Node JS - Youtube


0
有时候,用户的访问令牌可能会被盗取,而用户对此一无所知。由于用户不知道这次攻击,他们将无法手动通知我们。那么,对于给予攻击者完成攻击的时间(机会)来说,15分钟和整整一天之间会有很大的差异。因此,这就是为什么我们需要每隔“短时间”(例如每15分钟)自己“刷新”访问令牌的原因,我们不想把这个时间拖得太久(例如整整一天)。因此,OP在问题中提到的显然不是一个选项(将访问令牌的过期时间延长到与刷新令牌相同)。
我们至少有以下三个选项(我现在能想到的):
  1. 要求每个用户在短时间内重新输入其凭据以便提供新的访问令牌。但显然,这不是一个受欢迎的选项,因为这会打扰到用户。

  2. 与其使用单独的令牌进行刷新,不如更新同一访问令牌的过期时间。一旦发现重复请求过期延长,则将其视为潜在的令牌盗窃,使令牌无效,并要求用户重新验证身份。然而,这种方法也有一个很大的缺点,即在访问令牌被盗窃时,我们将无法意识到盗窃只要真正的所有者没有重新访问我们的服务(这甚至可能需要“几天”),攻击者可以延长被盗访问令牌的有效期,只要我们允许。现在,将其与下一个选项进行比较,即使用“刷新令牌”。

  3. 使用第二个令牌,称为“刷新令牌”,是我们的下一个选择。专门添加此令牌以扩展用户的登录至少具有以下三个好处:1. 无需像发送访问令牌一样频繁地发送此更敏感的令牌(即“每个”受保护端点的请求)。2. 我们可以请求更多信息“除了刷新令牌之外”,以发放新的访问令牌,例如API服务器的客户端密钥。因此,即使刷新令牌被盗窃,攻击者也无法使用它请求新的访问令牌。3. 我们隐含地告诉开发人员,刷新令牌是“更敏感的令牌”,他们必须更加注意其安全性,例如通过将其保留在攻击者客户端代码更不可访问的方式中,例如在带有httpOnly标记的cookie中。

HttpOnly Cookie是添加到浏览器Cookie的标签,可以防止客户端脚本访问数据。source 在生成Cookie时使用HttpOnly标志有助于减轻客户端脚本访问受保护Cookie的风险。HttpOnly Cookie最初由Microsoft Internet Explorer开发人员为Internet Explorer 6 SP1实现于2002年。source(感谢IE!)
因此,虽然攻击者仍然能够窃取两个令牌,但与其他选项相比,我们已经在一定程度上降低了风险。

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