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
呢?
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
呢?
access_token
非常长时间,且没有refresh_token
,那么在一天内,黑客可以获取此access_token
并访问所有受保护的资源!refresh_token
,则access_token
的生命周期很短,因此黑客难以攻击您的access_token
,因为它将在短时间内失效。只有使用不仅refresh_token
还要使用client_id
和client_secret
才能检索回access_token
,而黑客没有这些信息。关键在于扩展,保持资源服务器无状态。
服务器是无状态的,意味着不会检查任何存储以提供非常快速的响应。通过使用公钥验证令牌的签名来实现此功能。
在每个请求中检查access_token
。
只需检查access_token
的签名和过期日期即可获得响应,这样可以快速响应并允许扩展。
access_token
应具有短的到期时间(几分钟),因为如果泄露了access_token
,则无法撤销它,损害是有限的。
access_token
过期时才检查refresh_token
。(例如每2分钟)refresh_token
可以具有长的到期时间(几周/几个月),如果泄露了,则可以撤销。然而,有一个重要的注意事项,认证服务器的请求要少得多,因此可以处理负载,但是存储问题可能会成为问题,因为它必须存储所有的refresh_tokens
,如果用户急剧增加,这可能会成为问题。
由于刷新和访问令牌是充满语义的术语,术语转换可能会有所帮助?
在2020年,越来越多的人接受了刷新令牌也可以存在于浏览器中的事实(最初是针对后端系统提供的)- 请参见https://pragmaticwebsecurity.com/articles/oauthoidc/refresh-token-protection-implications。由于这个原因,重点从“可刷新性”(在没有用户的情况下,后端如何延长对API的访问权限)转向了“可撤销性”。
所以,根据我的看法,将刷新令牌视为可撤销令牌,将访问令牌视为不可撤销令牌(也许是快速到期的不可撤销令牌)更安全些。
作为一个关于良好实践的附注,在2021年,系统总是可以从可撤销令牌开始,并在授权服务器压力增加时转向不可撤销令牌。
我这里有一些额外的资源,可以更清楚地解释我们为什么需要刷新令牌。以下是其中一些资源的关键点:
authServer
和 resourceServer/s
的单独服务器
refresh token
,access token
并且也可以login
& logout
用户products
、reviews
等refresh_token
的一个用途是,我们不必每次需要新的access_token
时都将username and password (credentials)
通过网络(从前端到authServer)发送。这只需要在第一次(当您还没有refresh_token
时)进行,之后refresh_token
将从authServer得到新的access_token
,因此您可以继续向受保护的resourceServer发出请求。这里的优点是,由于用户不必每次提供凭据,因此用户的用户名和密码不容易被攻击者获得。refresh_token
的另一个主要用途是,假设在现实世界中,您的authServer比resourceServer更加安全(第三方服务如auth0、okta、azure等或您自己的实现)。您将只向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
,从而再次恢复正常。一些有用的资源
要求每个用户在短时间内重新输入其凭据以便提供新的访问令牌。但显然,这不是一个受欢迎的选项,因为这会打扰到用户。
与其使用单独的令牌进行刷新,不如更新同一访问令牌的过期时间。一旦发现重复请求过期延长,则将其视为潜在的令牌盗窃,使令牌无效,并要求用户重新验证身份。然而,这种方法也有一个很大的缺点,即在访问令牌被盗窃时,我们将无法意识到盗窃只要真正的所有者没有重新访问我们的服务(这甚至可能需要“几天”),攻击者可以延长被盗访问令牌的有效期,只要我们允许。现在,将其与下一个选项进行比较,即使用“刷新令牌”。
使用第二个令牌,称为“刷新令牌”,是我们的下一个选择。专门添加此令牌以扩展用户的登录至少具有以下三个好处:1. 无需像发送访问令牌一样频繁地发送此更敏感的令牌(即“每个”受保护端点的请求)。2. 我们可以请求更多信息“除了刷新令牌之外”,以发放新的访问令牌,例如API服务器的客户端密钥。因此,即使刷新令牌被盗窃,攻击者也无法使用它请求新的访问令牌。3. 我们隐含地告诉开发人员,刷新令牌是“更敏感的令牌”,他们必须更加注意其安全性,例如通过将其保留在攻击者客户端代码更不可访问的方式中,例如在带有httpOnly
标记的cookie中。