“刷新令牌”的目的是什么?

274

我有一个与YouTube直播API集成的程序。它运行定时器,因此相对容易编程,在50分钟内获取新的Access Token和Refresh Token。我的问题是,为什么这样做?

当我通过YouTube进行身份验证时,它提供了一个Refresh Token。然后,我使用该Refresh Token每小时左右获取一个新的Access Token。如果我拥有Refresh Token,我可以始终使用它来获取新的Access Token,因为它永远不会过期。因此,我不明白为什么这比一开始就给我一个Access Token并且不费力地使用整个Refresh Token系统更加安全。


2
请参见 https://dev59.com/5nA75IYBdhLWcg3wFEsI#57503520。 - mfaani
47
访问令牌是“持有人”令牌。这意味着不需要其他标识,访问令牌就足以冒充你。因此,它们应该始终短暂存在。另一方面,刷新令牌不是“持有人”令牌。当您向YouTube发送刷新令牌以获取新的访问令牌时,还必须发送client_id和client_secret。因此,刷新令牌可以保留更长时间,因为很少有可能同时泄露刷新令牌和client_secret。 - jmrah
11
为什么刷新令牌和客户端密钥不太可能被破解?所有令牌,包括访问令牌,在发送时都经过 HTTPS 加密,因此我认为它们始终是加密的。 - Olle Härstedt
7
我猜@OlleHärstedt的意思是,相较于访问令牌,减少了被攻击者以两种方式受到威胁的可能性。首先,因为刷新令牌在传输过程中花费的时间要少得多,攻击者进行中间人攻击(或其他类型的攻击)获取刷新令牌的机会更少。其次,如果攻击者要获取服务器的访问权限,则需要获取3个信息(令牌、ID和密钥),而不是只有一个(访问令牌),理论上看起来更难做到。 - jmrah
1
令牌也可以与IP地址绑定,这样可以增加额外的安全层。 - Peru
11个回答

175

刷新令牌基本上用于获取新的访问令牌。

为了清晰区分这两个令牌并避免混淆,在OAuth 2.0授权框架中给出了它们的功能:

  • 访问令牌是由授权服务器经资源所有者批准向第三方客户端发放的。客户端使用访问令牌来访问资源服务器上托管的受保护资源。
  • 刷新令牌是用于获取访问令牌的凭据。授权服务器向客户端发放刷新令牌,用于在当前访问令牌无效或过期时获取新的访问令牌,或者以相同或更窄的范围获取其他访问令牌。

现在回答您的问题,为何您仍然会被发放一个刷新令牌而不是安全地获取访问令牌,由Internet Engineering Task Force在刷新令牌中提供的主要原因是:

有一个安全原因,刷新令牌只会与授权服务器交换,而访问令牌会与资源服务器交换。这可以减轻“一个有效期为一小时的访问令牌和一个有效期为一年或撤销后依然有效的刷新令牌”与“一个没有刷新令牌仍然有效的访问令牌”的风险。

有关OAuth 2.0流程的更详细和完整信息,请尝试阅读以下参考资料:

  • SO帖子 - 为什么OAuth v2需要同时使用访问令牌和刷新令牌?

  • 11
    刷新令牌是否应该帮助获取新的刷新令牌? - Gherman
    19
    当访问令牌过期时,为什么不直接获取一个新的短期访问令牌?如果需要向服务器请求新的访问令牌,为什么需要长期的刷新令牌呢?或者说,使用刷新令牌后,是否真的不需要保持身份提供者 cookie 的有效性,并且可以基于刷新令牌发出新的访问令牌,即使 cookie 已经消失了,用户也必须输入其凭据才能获取新的访问令牌? - JustAMartin
    14
    作为OAuth2客户端,如果没有刷新令牌,我需要重新开始整个授权流程(让用户“登录”并再次授予我权限),以获得另一个访问令牌。刷新令牌可以绕过这个要求,作为一种“证明”,即我作为客户端已经获得了用户的许可请求访问令牌。 - jmrah
    42
    这个回答过于强调“是什么”,而缺乏“为什么”的解释。我认为给读者提供一个现实生活中的例子会更有益处。 - Sammy Taylor
    25
    @Sammy Taylor 完全同意。我简直不敢相信我读完了那整篇长文,最终却一无所获。 - 1mike12
    显示剩余4条评论

    88
    刷新令牌至少有两个作用。首先,刷新令牌是一种“证明”,OAuth2客户端已经收到用户的许可以访问他们的数据,因此可以再次请求新的访问令牌而无需用户完成整个OAuth2流程。其次,与长时间的访问令牌相比,它有助于提高整个安全流程。我将稍微详细地谈一下这两点。
    刷新令牌作为不惹恼用户的手段
    让我们通过一个例子来谈谈第一个目的。假设您是用户,正在使用希望与您的YouTube帐户数据交互的第三方客户端Web应用程序。一旦您授予客户端应用程序使用您的YouTube数据的权限,当其YouTube令牌过期时,您是否希望客户端应用程序再次提示您同意?如果YouTube令牌的过期时间很短,例如5分钟,那么每5分钟左右就会提示用户同意会变得有些烦人!OAuth2提出的解决“问题”的方法是使用刷新令牌。通过使用刷新令牌,访问令牌可以保持短暂(如果访问令牌被泄露或某种方式被盗窃,则这是可取的),而刷新令牌可以保持较长的寿命,允许客户端在一个过期时获取新的访问令牌,而不需要再次请求用户的许可。

    那么为什么需要一个刷新令牌呢?如果目的是为了不打扰用户进行权限请求,那么为什么客户端不能简单地说“嘿,授权服务器,我要另一个访问令牌。现在!”或者“嘿,授权服务器,这是我的过期令牌,给我一个新的!”? 那么,刷新令牌作为一种“证明”,证明客户端在某个原始时间点被用户授予了访问权限。 这个“证明”以刷新令牌由授权服务器数字签名的形式存在。 通过客户端呈现刷新令牌,授权服务器可以验证客户端在过去的某个时刻获得了用户的许可,而客户端无需再次提示用户。

    使用刷新令牌增加安全性

    然而,这引发了一个问题:“如果刷新令牌泄漏或被盗,或者简单地由恶意客户端应用程序保留而未经用户请求删除,会发生什么情况?攻击者不能继续使用刷新令牌无限期地(或直到其过期)获得有效的访问令牌吗?这个问题导致讨论我提到的第二个目的,即刷新令牌有助于提高安全性。

    访问令牌的问题在于,一旦获取到了访问令牌,它们只会被呈现给资源服务器(例如 YouTube)。因此,如果访问令牌被盗或者被篡改,怎样告诉资源服务器不再信任该令牌呢?实际上这是无法做到的。唯一的方法是更改授权服务器上的私钥签名(最初签署该令牌的密钥)。我想这样做很不方便,在某些情况下(如Auth0),也得不到支持。

    另一方面,刷新令牌需要频繁呈现给授权服务器。因此,如果一个刷新令牌遭到破坏,那么撤销或拒绝整个刷新令牌就很容易,而不必更改任何签名密钥。


    14
    请问需要翻译的内容是什么? - Leeish
    1
    @Leeish 在简单的登录场景中,例如使用用户名和密码进行登录,你是正确的。但在更复杂的场景中,例如使用 OTP 或 OAuth2 流程进行登录,需要使用 refresh_token。 - ehsan ahmadi
    4
    根据您发布的答案,可以说如果在某种情况下“资源服务器”和“授权服务器”是相同的(我的意思是例如一个网站既提供资源又自己进行授权),使用“刷新令牌”就不是那么有意义了吗?@jmrah - hamid-davodi

    33

    这里是来自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) 授权服务器对客户端进行身份验证并验证刷新令牌,如果有效,则发出新的访问令牌(以及可选的新刷新令牌)。


    2
    我在最后一步有疑问。使用刷新令牌发送刷新令牌是不是不好的做法?我应该不这样做吗? - Vignesh S
    @VigneshS 我不明白你的问题... 如果你的会话即将过期,你可以发送刷新令牌来获取新的访问和刷新令牌。 - Dennis Meissel
    @DennisMeissel 能否向我解释一下通过发送刷新令牌重新发行的新访问令牌是什么?新访问令牌会使用当前的刷新令牌作为新的访问令牌吗?例如,我当前的刷新令牌是123,重新发行新的访问令牌后,我会收到123作为新访问令牌的值吗? - undefined
    @Epple 不,当您向授权服务器发送有效的刷新令牌后,授权服务器会开始刷新过程:它会生成一个新的访问令牌和可选的新刷新令牌。同时,使用过的刷新令牌以及旧的访问令牌会过期。然而,旧的访问令牌并不总是在刷新后立即过期,这取决于具体的实现方式。 - undefined

    29

    仅使用访问令牌比同时使用访问令牌刷新令牌更加危险。

    例如,您仅使用访问令牌设置"100天"到期日期,但某一天,访问令牌被黑客窃取。现在,黑客有最多100天的时间自由地将访问令牌用于恶意目的。

    现在,您同时使用访问令牌设置"60分钟"到期日期刷新令牌设置"100天"到期日期,但某一天,访问令牌被黑客窃取。现在,黑客有最多60分钟的时间自由地将访问令牌用于恶意目的的机会要小得多。

    现在,你可能会想如果刷新令牌被盗了怎么办。实际上,如果刷新令牌被黑客盗取,黑客仍然有最多100天的时间自由使用刷新令牌进行不良目的。 但是刷新令牌被盗的概率要比访问令牌被盗的概率小得多,因为刷新令牌每60分钟只能用一次来刷新访问令牌(获取一个新的访问令牌),而访问令牌则会每次访问资源时使用,这是更频繁的。

    所以,最好同时使用访问令牌刷新令牌


    如果刷新令牌被盗,黑客可以使用它获取访问令牌,并在100天内无限次地进行任何操作(因为有了访问令牌)。 - cheiser
    如果攻击者获取了客户端数据,是否有可靠的解决方案来防止他获取这些数据?即使攻击者获得了客户端的访问权限,是否有任何措施可以确保JWT的安全性? - undefined
    好答案。关于长期过期的另一个要点是,你不能轻易地撤销它们。保持访问令牌的短期有效,意味着你可以撤销刷新令牌,然后黑客只能在短暂的时间内获得访问权限。 - undefined

    27

    @Teyam提到了一个关于OAuth v2为什么有访问令牌和刷新令牌的Stack Overflow帖子,但我更倾向于那里的另一个答案:https://dev59.com/5nA75IYBdhLWcg3wFEsI#12885823

    TL;DR refresh_token并不会增加安全性。它的目的是为了提高可扩展性和性能。所以,access_token 可以仅存储在一些快速临时存储(如内存)中。它还允许授权服务器和资源服务器分离。


    9
    除非出于安全原因,如@Teyam所提到的:“refresh_token只与授权服务器交换,而access_token则与资源服务器交换”。 - huyz
    10
    只有在我们假定授权服务器比资源服务器更加安全的情况下,这种方法才更加安全。如果不是这种情况,那么实际上它会变得不太安全。如果刷新令牌被攻击者获取,攻击者可以使用该令牌获取新的访问令牌。 - Arno van Lieshout
    3
    简而言之,这是真的吗? - mercury
    1
    我喜欢强调可扩展性,我认为这经常被误解了,我在这里总结一下:https://dev59.com/5nA75IYBdhLWcg3wFEsI#71932878 - Bernard Wiesner

    19
    access_token 更频繁使用,撤销功能不是很重要,因为它们的生命周期很短。

    refresh_token 使用较少,撤销功能至关重要,因为它们可以用于生成新的access_token

    验证签名令牌的成本较低,但撤销难度较大。

    验证存储在数据库中的令牌的成本高,但可以轻松撤销。

    因此,签名密钥可以用作access_token,以提高性能。

    存储在数据库中的密钥可以用作refresh_token,以便轻松撤销。

    如果没有refresh_token,很难找到一种提供低成本验证和易于撤销的机制。因此,refresh_token存在是出于性能原因。


    假设刷新令牌在请求中使用较少,因此更不容易被拦截,这种想法是否正确? - Benargee
    好答案。刷新令牌应该像密码一样对待,并进行昂贵的验证。 - mukunda

    16
    “所以我不清楚这比一开始直接给我一个访问令牌再不用理整个刷新令牌系统更安全。” 我也曾经遇到过同样的问题。简短的回答是,刷新令牌是必要的,以确保凭据没有过期。
    举个例子: 我有一个数据库,存储了你的医疗记录。你同意与你的配偶共享你的医疗记录。你的配偶使用他们的访问令牌从我的数据库中读取你的记录。两周后,你的配偶再次查看你的医疗记录,使用刷新令牌来确保他们仍然有权限(来自认证服务器)查看你的记录。刷新令牌绕过了需要你的配偶重新输入他们的凭据(用户名和密码)到认证服务器的步骤,但它确保了他们仍然有合法权利访问资源。一个永不过期的访问令牌将不知道你是否已经撤销了你的配偶访问你的医疗记录的权利。

    3
    即使访问令牌从未过期,如果我已经撤销了配偶访问我的医疗记录的权限,该访问令牌不会失效吗? - Krishnaraj
    1
    访问令牌通常短暂,大约在30到60分钟左右。而且很不可能有人在这30-60分钟内授予客户端应用程序对其数据(受保护资源)的授权并撤销它。但是,如果用户确实撤销了授权,则授权服务器将撤销访问令牌和刷新令牌。此外,一个好的客户端应用程序还应该自愿调用/revoke端点,以放弃接收者(在本例中为配偶)不再需要访问受保护资源时的令牌。这样,在不再需要令牌时,就不会有有效的令牌留下来。 - Naren

    10
    至少有三个相对应的原因,支持短周期的访问令牌和长周期的刷新令牌。

    承载令牌

    虽然您可以始终使用刷新令牌获取新的访问令牌,因为它永远不会过期,但攻击者通常不行。这是因为您使用刷新令牌必须提供一些证明您客户端身份的信息,例如提供 client_secret。而访问令牌是承载令牌,只需简单呈现即可,无需提供此类证明。
    将访问令牌的生命周期设置为短暂可以在某种程度上减轻访问令牌的无限权力。

    攻击面

    访问令牌与(可能多个)资源服务器交换,从而增加了泄漏的风险。刷新令牌只与授权服务器交换。
    同样,将访问令牌的寿命设置为短暂至少能够在一定程度上缓解这种情况。

    吊销

    可以将访问令牌实现为已签名的 JWT。在这种情况下,任何服务器(知道签名方的公钥,通常在某个众所周知的位置)都可以独立验证访问令牌的正确性。这允许 nicely decoupled 架构,因为资源服务器不必询问授权服务器进行授权。
    这种设置的缺点是无法吊销此类令牌(除非采取像吊销授权服务器的公钥这么激进的方法)。
    通过将访问令牌的生命周期设置短暂,可以让它们自行到期,而无需明确吊销。

    1
    refresh_token 模式可以使OAuth服务器保持控制,因此当出现像 access_tokenrefresh_token 泄露等不良情况时,服务器可以进行干预。
    例如,如果 access_tokenrefresh_token 被黑客获取,access_token 将很快过期,黑客可能会尝试刷新令牌,但是服务器现在有能力/控制来不再发放 access_token(考虑到服务器已经获取了泄漏的信息)。请注意保留HTML标签。

    1

    访问令牌的生命周期很短。一旦过期,您需要一个新的访问令牌才能访问受保护的资源。一种获取新访问令牌的方法是再次验证资源所有者并获取授权授予,然后获取访问令牌。但是,这将很麻烦。

    使用刷新令牌可以解决这个问题。它的生命周期很长。因此,您可以使用它来获取新的访问令牌,而无需与资源所有者交互。

    好吧,您可能会想,拥有长寿命的令牌以获取另一个寿命短暂的密钥有什么意义。即使刷新令牌被攻击者攻破,攻击者也不能从中获取访问令牌。原因是攻击者需要客户端凭据以及该刷新令牌。

    因此,为了提高安全性,访问令牌的生命周期很短(其他答案中提供了原因)。为避免每次访问令牌过期时都让资源所有者感到烦恼,OAuth 使用刷新令牌。


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