我有一个程序,与YouTube直播流媒体API集成。它在计时器上运行,所以它对我来说相对容易编程,每50分钟用刷新令牌获取一个新的访问令牌。我的问题是,为什么?
当我使用YouTube进行身份验证时,它给了我一个刷新令牌。然后我使用这个刷新令牌大约每小时获得一次新的访问令牌。如果我有刷新令牌,我总是可以使用它来获得一个新的访问令牌,因为它永远不会过期。所以我看不出这比从一开始就给我一个访问令牌而不打扰整个刷新令牌系统更安全。
基本上,刷新令牌是用来获得新的访问令牌的。
为了清楚地区分这两个令牌并避免混淆,下面是OAuth 2.0授权框架中给出的它们的函数:
- 访问令牌由授权服务器经过资源所有者的批准颁发给第三方客户端。客户端使用访问令牌访问由资源服务器托管的受保护资源。
- 刷新令牌是用于获取访问令牌的凭据。刷新令牌由授权服务器颁发给客户端,用于在当前访问令牌无效或过期时获取新的访问令牌,或获取具有相同或更窄范围的其他访问令牌。
现在,为了回答你的问题,为什么你仍然被颁发一个刷新令牌,而不仅仅是保护访问令牌,互联网工程任务组在刷新令牌中提供的主要原因是:
出于安全原因,
refresh_token
只与授权服务器交换,而access_token
与资源服务器交换。这降低了长期存在的access_token泄漏的风险:"访问令牌有效期为一小时,刷新令牌有效期为一年或直到被撤销"。Vs "访问令牌在没有刷新令牌的情况下仍然有效。"
有关OAuth 2.0 Flow的更详细和完整的信息,请尝试阅读以下参考资料:
- OAuth 2.0 Flow:服务器端web apps
- 互联网工程任务组(IETF)发布OAuth 2.0授权框架
- SO后-为什么OAuth v2有访问和刷新令牌?
刷新令牌至少有两个用途。首先,刷新令牌是一种"证明",证明OAuth2客户端已经从用户那里获得了访问其数据的权限,因此可以再次请求新的访问令牌,而无需用户通过整个OAuth2流程。其次,与长期使用的访问令牌相比,它有助于提高整个安全性流程。我将更详细地讨论这两点。
刷新令牌作为一种不惹恼用户的方法
让我们用一个例子来讨论第一个目的。假设您是一名用户,正在使用第三方客户端web应用程序,希望与您的YouTube帐户数据进行交互。一旦你授予权限给客户端应用程序使用你的YouTube数据,你想让客户端应用程序提示你的权限再次当它的YouTube令牌过期?如果YouTube令牌的到期时间很短,比如5分钟,会发生什么?如果客户端应用程序至少每5分钟提示一次您的权限,那就有点烦人了!OAuth2针对这个"问题"提出的解决方案是刷新令牌。通过使用刷新令牌,访问令牌可以保持短暂(这在访问令牌泄露或被盗的情况下是可取的),刷新令牌可以保持较长的(er)寿命,允许客户端在一个访问令牌到期时获得新的访问令牌,而无需再次要求用户的许可。
但是为什么是刷新令牌呢?如果目的是不向用户发送权限请求,那么客户端为什么不能简单地说"嘿,授权服务器,我想要另一个访问令牌"呢?现在!"?或者,"嘿,授权服务器,这是我过期的令牌,给我一个新的!"刷新令牌可以作为一种"证明"客户端在某个原始时间点被用户授予访问权限。这个"proof"是由授权服务器进行数字签名的刷新令牌的形式。通过客户端提供刷新令牌,授权服务器可以验证客户端在过去的某个时刻收到了来自用户的许可,并且客户端不必再次提示用户。
刷新令牌作为提高安全性的手段
然而,这提出了一个问题,"如果刷新令牌泄露或被盗,或者只是被恶意的客户端应用程序保留,而不应用户的请求删除它,会发生什么?"攻击者不能继续使用刷新令牌来无限期地获得有效的访问令牌(或直到它过期)吗?这个问题导致讨论我提到的第二个目的,刷新令牌有助于更安全的流。
访问令牌出现的问题是,一旦获得,它们只会呈现给资源服务器(例如YouTube)。因此,如果访问令牌被盗或泄露,如何告诉资源服务器不要信任该令牌?嗯,你真的不能。唯一的方法是更改授权服务器上的私有签名密钥(最初为令牌签名的密钥)。我想这样做很不方便,而且在某些情况下(比如Auth0),是不支持的。
另一方面,刷新令牌需要频繁地呈现给授权服务器,因此,如果一个令牌被泄露,那么撤销或拒绝整个刷新令牌是很简单的,而不必更改任何签名密钥。
以下是OAuth 2.0文档中的信息。
刷新令牌用于在当前访问令牌无效或过期时获得新的访问令牌,或用于获得具有相同或更窄范围的额外访问令牌(访问令牌可能具有比资源所有者授权的更短的生存期和更少的权限)。
+--------+ +---------------+
| |--(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)授权服务器对客户端进行认证和验证刷新令牌,如果有效,则发出新的访问令牌(和,(可选,一个新的刷新令牌)。
@Teyam提到SO post为什么OAuth v2同时具有访问和刷新令牌?但我更喜欢另一个答案:https://stackoverflow.com/a/12885823/254109
TL;DR refresh_token
不能提高安全性。它的目的是提高可伸缩性和性能。然后,access_token
可能只是存储在一些快速的临时存储(如内存)中。它还允许授权和资源服务器分离。
仅使用访问令牌比同时使用访问令牌和刷新令牌风险要大得多。
例如,只使用访问令牌 set "100天"但是有一天,访问令牌被黑客窃取。现在,黑客有很大的机会可以自由使用访问令牌100天,作为恶意目的。
现在,您使用访问令牌设置"60分钟"和刷新令牌设置"100天";但是有一天,访问令牌被黑客窃取。现在,黑客有更小的机会自由使用访问令牌60分钟作为恶意目的的最大值。
现在,您将考虑刷新令牌是否被盗。实际上,如果刷新令牌被黑客窃取,黑客仍然有很大的机会自由使用刷新令牌100天作为恶意目的。但是刷新令牌被盗的概率远小于访问令牌被盗的概率,因为刷新令牌每60分钟才使用一次刷新访问令牌(以获得新的访问令牌)而访问令牌每次访问资源时都使用,这要频繁得多。
因此,您最好同时使用访问令牌和刷新令牌。"所以我看不出这比从一开始就给我一个访问令牌而不打扰整个刷新令牌系统更安全。"我也纠结于同样的问题。简单地说,刷新令牌是确保凭据没有过期所必需的。
下面的例子可能会有所帮助:我有一个存储你医疗记录的数据库。你同意与你的配偶分享你的医疗记录。你的配偶使用他们的访问令牌从我的数据库中读取你的记录。从现在起两周后,您的配偶再次检查您的医疗记录,刷新令牌用于确保他们仍然拥有(来自身份验证服务器)查看您的记录的权限。刷新令牌绕过了您的配偶向身份验证服务器重新输入其凭据(用户名和密码)的需要,但它确实确保他们仍然具有访问资源的合法性。永不过期的访问令牌将无法知道您是否已撤销了您的配偶访问您医疗记录的权利。
access_token
s使用更频繁,撤销能力不是很重要,因为它们是短暂的。
refresh_token
的使用频率较低,撤销的能力是至关重要的,因为它们可以用来生成新的access_token
。
验证已签名令牌的成本较低,但撤销很困难。
验证存储在数据库中的令牌成本很高,但很容易撤销。
因此,签名密钥可以用作access_token
s来提高性能。
数据库存储的键可以用作refresh_token
s,以便于撤销它们。
如果没有refresh_token
,很难找到一种低成本验证和容易撤销能力的机制。所以refresh_token
是由于性能原因而存在的。
使用短时间访问令牌和长时间刷新令牌至少有3个相关的原因。
无记名标记
从原来的问题:
如果我有刷新令牌,我总是可以使用它来获得一个新的访问令牌,因为它永远不会过期。
尽管您可能总是能够使用刷新令牌获得新的访问令牌,但攻击者通常不会。这是因为你对刷新令牌的使用与你作为客户端的身份证明相结合,例如通过提供你的client_secret。访问令牌不需要这样的证明,因为它是不记名令牌,也就是说,只要出示它们就足够了。
让访问令牌是短暂的,在某种程度上减轻了访问令牌的无限权力。
攻击面
访问令牌与(可能有许多)资源服务器交换,这增加了泄漏的可能性。刷新令牌只与授权服务器交换。同样,访问令牌的短寿命至少是某种程度的缓解。
撤销将访问令牌实现为签名的jwt是可能的(也是常见的)。在这种情况下,任何服务器(知道签名方的公钥,通常位于某个众所周知的位置)都可以独立地验证访问令牌的正确性。这允许很好地解耦体系结构,从某种意义上说,资源服务器不必询问授权服务器有关授权的信息。
这种设置的缺点是这样的令牌不能被撤销(没有任何像撤销授权服务器的公钥那样激烈的事情)。
通过使访问令牌短暂存在,可以简单地允许它们耗尽,而不是显式地撤销它们。
访问令牌的生命周期较短。一旦它过期,您需要一个新的访问令牌来访问受保护的资源。获取新的访问令牌的一种方法是再次对资源所有者进行身份验证并获得授权授予,然后再获取访问令牌。但是,这会很烦人。
这个问题可以用刷新令牌解决。寿命长。因此,您可以使用它来获得新的访问令牌,而无需与资源所有者交互。
好吧,你可能会想,用长生命周期的令牌来获得另一个短生命周期的密钥有什么意义呢?嗯,即使刷新令牌被破坏,攻击者也无法从中获取访问令牌。原因是攻击者需要客户端凭据以及刷新令牌。
因此,访问令牌将具有较短的生命周期(其原因在其他答案中可用),以提高安全性。为了避免在访问令牌到期时惹恼资源所有者,OAuth使用刷新令牌。refresh_token
模式使OAuth服务器处于控制之中,因此当不良发生时,服务器可以进行干预,例如access_token
和refresh_token
被泄露。
。
如果access_token
和refresh_token
落入黑客手中,access_token
将很快过期,黑客可能会尝试刷新令牌,但服务器现在有能力/控制不再发出access_token
(考虑到服务器获得了泄漏的信息)。
这是一次很好的学习经历,对令牌、刷新令牌和缓存令牌有了一些了解。然而,(我很好奇,我在这里没有给出任何建议)我们可以使用在使用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();
}