我有一个与 YouTube Live Streaming API 集成的程序。它在计时器上运行,因此我相对容易编程以每 50 分钟使用刷新令牌获取新的访问令牌。我的问题是,为什么?
当我通过 YouTube 进行身份验证时,它给了我一个刷新令牌。然后,我使用此刷新令牌大约每小时获取一次新的访问令牌。如果我有刷新令牌,我总是可以使用它来获取新的访问令牌,因为它永不过期。因此,我看不出这比从一开始就给我一个访问令牌而不是打扰整个刷新令牌系统更安全。
基本上,刷新令牌用于获取新的访问令牌。
为了清楚地区分这两个标记并避免混淆,The OAuth 2.0 Authorization Framework 中给出了它们的功能:
访问令牌由授权服务器在资源所有者的批准下颁发给第三方客户端。客户端使用访问令牌访问资源服务器托管的受保护资源。刷新令牌是用于获取访问令牌的凭据。刷新令牌由授权服务器下发给客户端,用于在当前访问令牌失效或过期时获取新的访问令牌,或者获取范围相同或更窄的额外访问令牌。
现在,要回答您为什么仍会获得刷新令牌而不是仅仅保护访问令牌的问题,Internet 工程任务组在 Refresh tokens 中提供的主要原因是:
出于安全原因,refresh_token 只与授权服务器交换,而 access_token 与资源服务器交换。这降低了长期 access_token 在“一个小时内有效的访问令牌,具有一年有效或直到撤销有效的刷新令牌”与“在没有刷新的情况下有效直到撤销的访问令牌”中泄漏的风险令牌。”
有关 OAuth 2.0 Flow 的更详细和完整的信息,请尝试阅读以下参考资料:
OAuth 2.0 流程:服务器端 Web 应用程序
Internet Engineering Task Force (IETF) 发布的 OAuth 2.0 授权框架
SO post - 为什么 OAuth v2 既有访问令牌又有刷新令牌?
刷新令牌至少有两个用途。首先,刷新令牌是一种“证明”,表明 OAuth2 客户端已经从用户那里获得了访问其数据的权限,因此可以再次请求新的访问令牌,而无需用户完成整个 OAuth2 流程。其次,与长期存在的访问令牌相比,它有助于提高整个安全流程。我将更详细地讨论这两点。
刷新令牌作为不惹恼用户的手段
让我们用一个例子来谈谈第一个目的。假设您是一名用户,正在使用想要与您的 YouTube 帐户数据进行交互的第三方客户端 Web 应用程序。一旦您授予客户端应用程序使用您的 YouTube 数据的权限,您是否希望客户端应用程序在其 YouTube 令牌过期时再次提示您获得许可?如果 YouTube 令牌的到期时间非常短,例如 5 分钟,会发生什么情况。让客户端应用程序至少每 5 分钟提示一次您的许可会有点烦人! OAuth2 针对这个“问题”提出的解决方案是刷新令牌。通过使用刷新令牌,访问令牌可以保持短暂的状态(如果访问令牌以某种方式泄露或被盗,这是可取的),并且刷新令牌可以保持较长(更)寿命,允许客户端获得新的访问权限令牌过期而不需要用户的许可(再次)。
但为什么要刷新令牌?如果重点是不通过权限请求来干扰用户,那么为什么客户端不能简单地说“嘿,授权服务器,我想要另一个访问令牌。现在!”?或者,“嘿授权服务器,这是我过期的令牌,给我一个新的!”。好吧,刷新令牌用作一种“证明”,即客户端在某个原始时间点被用户授予访问权限。这个“证明”是由授权服务器数字签名的刷新令牌的形式。通过客户端提供刷新令牌,授权服务器可以验证客户端是否在过去的某个时间收到了用户的许可,并且客户端不必再次提示用户。
刷新令牌作为提高安全性的一种手段
然而,这就提出了一个问题,“好吧,如果刷新令牌被泄露或被盗,或者只是被恶意客户端应用程序保留而没有根据用户的请求删除它,会发生什么?攻击者不能继续使用刷新令牌无限期地(或直到它过期)获得有效的访问令牌?这个问题导致讨论我提到的第二个目的,即刷新令牌有助于更安全的流程。
访问令牌出现的问题是,一旦获得,它们只会呈现给资源服务器(例如 YouTube)。因此,如果访问令牌被盗或泄露,您如何告诉资源服务器不要信任该令牌?好吧,你真的不能。唯一的方法是更改授权服务器上的私有签名密钥(首先签署令牌的密钥)。我想这样做不方便,并且在某些情况下(如 Auth0)不支持。
另一方面,刷新令牌需要频繁地提交给授权服务器,因此如果一个被破坏,那么撤销或拒绝整个刷新令牌是微不足道的,而不必更改任何签名密钥。
@Teyam 提到 SO 帖子为什么 OAuth v2 同时具有访问和刷新令牌?但我更喜欢那里的另一个答案:https://stackoverflow.com/a/12885823/254109
TL;DR refresh_token
不会带来更高的安全性。其目的是提高可扩展性和性能。然后,access_token
可能只存储在一些快速的临时存储(如内存)中。它也允许授权和资源服务器分离。
“所以我不认为这比从一开始就给我一个访问令牌而不用打扰整个刷新令牌系统更安全。”我在同一个问题上挣扎。简短的回答是刷新令牌是确保凭据没有过期所必需的。
一个例子可能会有所帮助:我有一个存储您的医疗记录的数据库。您同意与您的配偶分享您的医疗记录。您的配偶使用他们的访问令牌从我的数据库中读取您的记录。两周后,您的配偶再次检查您的医疗记录,并使用刷新令牌确保他们仍然有权(来自身份验证服务器)查看您的记录。刷新令牌绕过了您的配偶将其凭据(用户名和密码)重新输入到身份验证服务器的需要,但它确实确保了他们仍然具有访问资源的合法性。永不过期的访问令牌不会知道您是否撤销了配偶访问您的医疗记录的权利。
以下是来自 OAuth 2.0 documentation 的信息。
Refresh tokens 用于在当前访问令牌失效或过期时获取新的 access token,或获取具有相同或更窄范围的额外访问令牌(访问令牌的生命周期可能比资源所有者授权的权限更短,权限也更少)。
+--------+ +---------------+
| |--(A)------- Authorization Grant --------->| |
| | | |
| |<-(B)----------- Access Token -------------| |
| | & Refresh Token | |
| | | |
| | +----------+ | |
| |--(C)---- Access Token ---->| | | |
| | | | | |
| |<-(D)- Protected Resource --| Resource | | Authorization |
| Client | | Server | | Server |
| |--(E)---- Access Token ---->| | | |
| | | | | |
| |<-(F)- Invalid Token Error -| | | |
| | +----------+ | |
| | | |
| |--(G)----------- Refresh Token ----------->| |
| | | |
| |<-(H)----------- Access Token -------------| |
+--------+ & Optional Refresh Token +---------------+
(A) 客户端通过与授权服务器进行身份验证并提供授权许可来请求访问令牌。
(B) 授权服务器对客户端进行身份验证并验证授权授予,如果有效,则颁发访问令牌和刷新令牌。
(C) 客户端通过提供访问令牌向资源服务器发出受保护的资源请求。
(D) 资源服务器验证访问令牌,如果有效,则为请求提供服务。
(E) 重复步骤 (C) 和 (D) 直到访问令牌过期。如果客户端知道访问令牌过期,则跳到步骤(G);否则,它会发出另一个受保护的资源请求。
(F) 由于访问令牌无效,资源服务器返回无效令牌错误。
(G) 客户端通过与授权服务器进行身份验证并提供刷新令牌来请求新的访问令牌。客户端身份验证要求基于客户端类型和授权服务器策略。
(H) 授权服务器对客户端进行身份验证并验证刷新令牌,如果有效,则发出新的访问令牌(以及,可选地,新的刷新令牌)。
access_token
更频繁地使用,并且撤销的能力不是很重要,因为它们是短暂的。
refresh_token
使用频率较低,撤销能力至关重要,因为它们可用于生成新的 access_token
。
验证签名令牌的成本较低,但撤销却很困难。
验证存储在数据库中的令牌成本高昂,但很容易撤销。
因此,签名密钥可用作 access_token
以提高性能。
Db 存储的密钥可用作 refresh_token
,以便轻松撤销它们。
如果没有refresh_token
,则很难找到一种提供低成本验证和易于撤销能力的机制。所以 refresh_token
由于性能原因而存在。
拥有短期访问令牌和长期刷新令牌至少有 3 个相关的原因。
不记名令牌
从原来的问题:
如果我有刷新令牌,我总是可以使用它来获取新的访问令牌,因为它永不过期。
尽管您可能总是能够使用刷新令牌获得新的访问令牌,但攻击者通常可能不会。这是因为您对刷新令牌的使用与您作为客户端的一些身份证明相结合,例如通过提供您的 client_secret。对于作为不记名令牌的访问令牌不需要这样的证明,即简单地呈现它们就足够了。
访问令牌是短暂的,这在一定程度上减轻了访问令牌的这种无限权力。
攻击面
访问令牌与(可能很多)资源服务器交换,这增加了泄漏的机会。刷新令牌只与授权服务器交换。
同样,访问令牌的短暂性至少是某种程度的缓解措施。
撤销
将访问令牌实现为签名的 JWT 是可能的(并且很常见)。在这种情况下,任何服务器(知道签名方的公钥,通常位于某个众所周知的位置)都可以独立验证访问令牌的正确性。这允许很好地解耦架构,因为资源服务器不必向授权服务器询问授权。
这种设置的缺点是不能撤销这样的令牌(没有像撤销授权服务器的公钥那样激烈的事情)。
通过使访问令牌的寿命很短,可以简单地允许它们用完而不是明确地撤销。
仅使用 Access Token 比同时使用 Access Token 和 Refresh Token 风险更大。
例如,如果你只使用Access Token,然后将Access Token的长有效期设置为100天,那么最终Access Token被黑客窃取,黑客可以获得最多100天免费使用Access Token的大机会。不好的目的。
但是,如果您同时使用 Access Token 和 Refresh Token,然后将较短的有效期设置为 60 分钟为 Access Token,将较长的有效期设置为 100 天为 Refresh Token,那么最终 Access Token 被黑客窃取,黑客获得的机会要小得多。出于不良目的,最多可免费使用 60 分钟的访问令牌。
现在,你会想如果刷新令牌被盗。实际上,如果 Refresh Token 被黑客盗取,黑客仍然可以有很大的机会免费使用 Refresh Token 最多 100 天用于不良目的。但是Refresh Token被盗的概率远小于Access Token被盗的概率,因为Refresh Token每60分钟只使用一次来刷新Access Token(获取一个新的Access Token),而Access Token是每次访问资源的时候使用的,这很多更频繁。
因此,您最好同时使用访问令牌和刷新令牌。
访问令牌的寿命很短。一旦过期,您需要一个新的访问令牌来访问受保护的资源。获得新访问令牌的一种方法再次验证资源所有者并获得授权授予然后获得访问令牌。但是,这会很烦人。
这个问题可以通过刷新令牌来解决。它的寿命很长。因此,您可以使用它来获取新的访问令牌,而无需与资源所有者交互。
好吧,你可能会想,拥有长寿命的令牌来获得另一个寿命短的密钥有什么意义。好吧,即使刷新令牌被泄露,攻击者也不能仅仅从中获取访问令牌。原因是攻击者需要客户端凭据以及刷新令牌。
因此,访问令牌将具有较短的生命周期(原因可在其他答案中找到)以提高安全性。为了避免资源所有者在访问令牌过期时烦人,OAuth 使用刷新令牌。
这是一次很好的学习体验,对令牌、刷新令牌和缓存有一些了解。但是,(我很好奇,我在这里不提供任何建议)在使用 Microsoft Identity 平台时,我们可以使用用户登录后返回的代码吗?我们是否可以只存储 CodeIdToken,并在需要时使用它来获取新的访问令牌?因为我在想我们用它来获取访问令牌,那么我们应该每次都使用它来重新生成访问令牌吗?
...
ResponseType = OpenIdConnectResponseType.CodeIdToken,
...
和
private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
{
IConfidentialClientApplication clientApp = MsalAppBuilder.BuildConfidentialClientApplication();
AuthenticationResult result = await clientApp.AcquireTokenByAuthorizationCode(new[] { "User.Read" }, context.Code)
.ExecuteAsync();
}
refresh_token
模式使 OAuth 服务器处于控制之中,因此服务器可以在发生诸如 access_token
和 refresh_token
泄露之类的不良情况时进行干预。
例如
如果 access_token
和 refresh_token
落入黑客手中,access_token
将很快过期,黑客可能会尝试刷新令牌,但服务器现在有能力/控制不再发出 access_token
(考虑服务器得到了泄漏的信息)。
不定期副业成功案例分享