我有一个程序,与YouTube直播API集成。它在计时器上运行,所以对我来说,每50分钟用刷新令牌获取一个新的访问令牌相对容易。我的问题是,为什么?

当我通过YouTube认证时,它给了我一个刷新令牌。然后,我大约每小时使用这个刷新令牌来获得一个新的访问令牌。如果我有刷新令牌,我总是可以使用它来获得一个新的访问令牌,因为它永远不会过期。因此,我不认为这比从一开始就给我一个访问令牌而不打扰整个刷新令牌系统更安全。


当前回答

这是一次很好的学习经历,了解了令牌、刷新令牌和缓存它。然而,(我很好奇,我在这里不给出任何建议)我们可以使用用户登录后返回的代码,当使用微软身份平台时。我们是否可以只存储CodeIdToken,并在需要时使用它来获取新的访问令牌?因为我在想,我们用它来获得访问令牌,那么我们应该每次都用来重新生成访问令牌吗?

 ...
 ResponseType = OpenIdConnectResponseType.CodeIdToken,
...

and

private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
    {
        IConfidentialClientApplication clientApp = MsalAppBuilder.BuildConfidentialClientApplication();
        AuthenticationResult result = await clientApp.AcquireTokenByAuthorizationCode(new[] { "User.Read" }, context.Code)
          .ExecuteAsync();
    }
    

其他回答

下面是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)授权服务器对客户端进行身份验证和验证 刷新令牌,如果有效,发出一个新的访问令牌(并且, 可选的,一个新的刷新令牌)。

使用短时间的访问令牌和长时间的刷新令牌至少有3个相关的原因。

不记名的令牌

从最初的问题:

如果我有刷新令牌,我总是可以使用它来获得一个新的访问令牌,因为它永远不会过期。

虽然您可能总是能够使用刷新令牌获得新的访问令牌,但攻击者通常不能。这是因为你对刷新令牌的使用与你作为客户端的身份证明相结合,例如通过提供你的client_secret。访问令牌不需要这样的证明,因为访问令牌是持名令牌,也就是说,简单地呈现它们就足够了。

如果访问令牌是短期的,则在一定程度上减轻了这种访问令牌的无限功能。

攻击面

访问令牌与(可能有许多)资源服务器交换,这增加了泄漏的机会。刷新令牌只与授权服务器交换。

同样,访问令牌的短寿命至少是某种程度上的缓解。

撤销

将访问令牌实现为有签名的jwt是可能的(也是常见的)。在这种情况下,任何服务器(知道签名方的公钥,通常位于某个众所周知的位置)都可以独立地验证访问令牌的正确性。这可以很好地实现体系结构的解耦,因为资源服务器不必向授权服务器询问授权。

这种设置的缺点是不能撤销这样的令牌(不需要像撤销授权服务器的公钥那样激烈的操作)。

通过使访问令牌的生命周期很短,可以简单地允许它们运行完,而不是显式地撤销。

@Teyam提到SO帖子为什么OAuth v2同时拥有访问和刷新令牌?但我更喜欢另一个答案:https://stackoverflow.com/a/12885823/254109

DR refresh_token不会增加安全性。它的目的是提高可伸缩性和性能。然后,access_token可以存储在一些快速的临时存储中(如内存)。它还允许授权和资源服务器分离。

只使用访问令牌比同时使用访问令牌和刷新令牌风险大得多。

例如,您只使用访问令牌设置“100天”有效期,但一天,访问令牌被黑客窃取。现在,黑客有很大的机会自由使用访问令牌100天,作为一个坏的目的。

现在,您使用访问令牌集“60分钟”到期日期和刷新令牌集“100天”到期日期,但有一天,访问令牌被黑客窃取。现在,黑客自由使用访问令牌的机会要小得多,最多只能使用60分钟。

现在,您会认为刷新令牌是否被盗。实际上,如果刷新令牌被黑客窃取,黑客仍然有很大的机会免费使用刷新令牌,最多100天用于不良目的。但是,刷新令牌被盗的概率远低于访问令牌被盗的概率,因为刷新令牌每60分钟才使用一次来刷新访问令牌(以获得新的访问令牌),而访问令牌则在每次访问资源时使用,这要频繁得多。

因此,您最好同时使用访问令牌和刷新令牌。

这是一次很好的学习经历,了解了令牌、刷新令牌和缓存它。然而,(我很好奇,我在这里不给出任何建议)我们可以使用用户登录后返回的代码,当使用微软身份平台时。我们是否可以只存储CodeIdToken,并在需要时使用它来获取新的访问令牌?因为我在想,我们用它来获得访问令牌,那么我们应该每次都用来重新生成访问令牌吗?

 ...
 ResponseType = OpenIdConnectResponseType.CodeIdToken,
...

and

private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
    {
        IConfidentialClientApplication clientApp = MsalAppBuilder.BuildConfidentialClientApplication();
        AuthenticationResult result = await clientApp.AcquireTokenByAuthorizationCode(new[] { "User.Read" }, context.Code)
          .ExecuteAsync();
    }