OAuth 2.0协议草案的第4.2节指出,授权服务器可以返回access_token(用于通过资源验证自己)和refresh_token,refresh_taken纯粹用于创建新的access_token:

https://www.rfc-editor.org/rfc/rfc6749#section-4.2

为什么两者都有?为什么不让access_token和refresh_token一样长,而不设置refresh_taken?


当前回答

Catchdave提供的讨论链接还有Dick Hardt提出的另一个有效的观点(原始的,死链接),我认为除了上面写的内容之外,这里还值得一提:

我记得刷新令牌是为了安全和撤销。<...>撤销:如果访问令牌是自包含的,则可以通过不发布新的访问令牌来撤销授权。资源不需要查询授权服务器以查看访问令牌是否有效。这简化了访问令牌验证,并使扩展和支持多个授权服务器更加容易。当访问令牌有效但授权被撤销时,有一个时间窗口。

事实上,在资源服务器和授权服务器是同一个实体的情况下,并且用户和其中任何一个之间的连接(通常)都是同样安全的,那么将刷新令牌与访问令牌分开并没有多大意义。

尽管如引用中所述,刷新令牌的另一个作用是确保用户可以随时(例如通过其配置文件中的web界面)撤销访问令牌,同时保持系统的可伸缩性。

通常,令牌可以是指向服务器数据库中特定记录的随机标识符,也可以包含自身的所有信息(当然,这些信息必须使用MAC进行签名)。

具有长期访问令牌的系统应该如何工作

服务器允许客户端通过发出令牌访问预定义范围内的用户数据。由于我们希望保持令牌的可撤销性,我们必须在数据库中存储令牌以及设置或取消设置的标志“已撤销”(否则,如何使用自包含令牌?)。数据库可以包含多达len(用户)x len(注册客户端)x len(范围组合)的记录。然后,每个API请求都必须命中数据库。虽然对执行O(1)的数据库进行查询非常简单,但单点故障本身可能会对系统的可伸缩性和性能产生负面影响。

具有长期刷新令牌和短期访问令牌的系统应该如何工作

在这里,我们发布两个密钥:带有数据库中相应记录的随机刷新令牌,以及签名的自包含访问令牌,其中包含过期时间戳字段。

由于访问令牌是自包含的,因此我们根本不必访问数据库来检查其有效性。我们所要做的就是解码令牌并验证签名和时间戳。

尽管如此,我们仍然需要保留刷新令牌的数据库,但对该数据库的请求数量通常由访问令牌的寿命定义(寿命越长,访问率越低)。

为了撤销特定用户对客户端的访问,我们应该将相应的刷新令牌标记为“已撤销”(或完全删除),并停止发布新的访问令牌。很明显,在一个窗口中,刷新令牌已被撤销,但其访问令牌可能仍然有效。

权衡取舍

刷新令牌部分消除了访问令牌数据库的SPoF(单点故障),但它们有一些明显的缺点。

“窗口”。事件“用户撤销访问”和“保证撤销访问”之间的时间间隔。客户端逻辑的复杂性。无刷新令牌使用访问令牌发送API请求如果访问令牌无效,则失败并要求用户重新验证带刷新令牌使用访问令牌发送API请求如果访问令牌无效,请尝试使用刷新令牌更新它如果刷新请求通过,则更新访问令牌并重新发送初始API请求如果刷新请求失败,请要求用户重新验证

我希望这个答案确实有意义,有助于某人做出更深思熟虑的决定。我还想指出,一些著名的OAuth2提供商,包括github和foursquare,采用了没有刷新令牌的协议,并对此感到满意。

其他回答

为了进一步简化B T的答案:当您通常不希望用户再次输入凭据,但仍然希望能够撤销权限(通过撤销刷新令牌)时,请使用刷新令牌

您不能撤销访问令牌,只能撤销刷新令牌。

假设您使access_token持续很长时间,并且没有refresh_token,那么在一天之内,黑客就可以访问所有受保护的资源!

但如果你有refresh_token,access_token的生存时间很短,所以黑客很难破解你的access_toke,因为它在短时间后将无效。Access_token只能通过不仅使用refresh_token,而且还可以通过client_id和client_secret(黑客没有)检索回来。

这个答案是在两位高级开发人员(约翰·布莱顿和大卫·詹内斯)的帮助下得出的。

使用刷新令牌的主要原因是减少攻击面。

假设没有刷新键,让我们来看看这个示例:

一座大楼有80扇门。所有车门都用同一把钥匙打开。钥匙每30分钟更换一次。在30分钟结束时,我必须把旧钥匙交给钥匙制造商,并获得一把新钥匙。

如果我是黑客,拿到了你的钥匙,那么在30分钟结束后,我会把它快递给钥匙制造商,并获得一把新钥匙。无论换钥匙,我都能连续打开所有车门。

问:在这30分钟里,我有多少次破解钥匙的机会?每次你使用密钥时,我都有80次黑客攻击的机会(把这看作是发出网络请求并传递访问令牌以识别自己)。这是80倍的攻击面。

现在让我们来看看同一个例子,但这次我们假设有一个刷新键。

一座大楼有80扇门。所有车门都用同一把钥匙打开。钥匙每30分钟更换一次。要获取新密钥,我无法传递旧的访问令牌。我只能通过刷新键。

如果我是黑客并得到了你的密钥,我可以使用它30分钟,但在30分钟结束时,将它发送给密钥制作者没有任何价值。如果我这样做了,那么密钥制作者只会说“此令牌已过期。您需要刷新令牌。”为了能够扩展我的黑客攻击,我必须将信使黑客攻击给密钥制作者。信使有一个不同的密钥(将其视为刷新令牌)。

问题:在30分钟内,我有多少次违反刷新键的黑客攻击机会?80? 不,我只有一次黑客攻击机会。在这段时间里,快递员与钥匙制造商进行沟通。这是1X攻击面。我确实有80次破解钥匙的机会,但30分钟后就不行了。


服务器将根据凭证和JWT的签名(通常)验证访问令牌。

访问令牌泄漏是不好的,但一旦过期,它对攻击者不再有用。刷新令牌泄漏的情况要糟糕得多,但估计可能性较小。(我认为,刷新令牌泄漏的可能性是否比访问令牌泄漏的概率低得多,这是一个问题,但这就是想法。)

重点是访问令牌被添加到您发出的每个请求中,而刷新令牌仅在刷新流期间使用所以MITM看到代币的可能性很小

频率有助于攻击者。像SSL中的潜在安全漏洞、客户端中的潜在的安全漏洞以及服务器中潜在的安全缺陷等令人心碎的漏洞都使泄漏成为可能。

此外,如果授权服务器与处理其他客户端请求的应用服务器分离,那么该应用服务器将永远不会看到刷新令牌。它只会看到不会持续很久的访问令牌。

分隔有利于安全。

最后但并非最不重要的刷新令牌可以被旋转。意思是“每次客户端请求将刷新令牌交换为新的访问令牌时,都会返回新的刷新令牌”。随着刷新令牌的不断交换和失效,威胁降低。举个例子:令牌通常在TTL之后过期,通常是一小时。

刷新令牌并不总是,但通常会在使用时被撤销,并发出新的令牌。这意味着,如果您在检索新的刷新令牌时发生网络故障,那么下次发送该刷新令牌时,它将被视为已吊销,您必须登录。

有关旋转的更多信息,请参阅此处和此处

总结

降低频率分区令牌的轮换(更快的失效)和更精细的管理(过期时间或请求数量)。

所有这些都有助于减轻威胁

关于这个问题的另一个观点,请看这个令人敬畏的答案


刷新令牌与什么无关?

通过刷新令牌更新/撤销访问级别的能力是选择使用刷新令牌的一个副产品,否则独立访问令牌可能会被撤销,或在其过期时修改其访问级别,用户将获得新令牌

我在这里获得了一些额外的资源,这些资源澄清了我们为什么需要refresh_token的某些问题。这些资源的一些要点如下:

在现实世界中,最好使用名为authServer和resourceServer/s的独立服务器authServer-仅用于身份验证和授权。该服务器的职责是发布刷新令牌、访问令牌以及登录和注销用户resourceServer-此服务器(也可以是负载平衡的多个服务器)提供受保护的数据。例如,这些数据可以像电子商务项目中的产品、评论等refresh_token的一个用途是,每次需要新的access_token时,我们不必通过网络(从前端到authServer)发送用户名和密码(凭据)。这应该只在第一次完成(当您还没有refresh_token时),refresh_taken将立即从authServer获取新的access_token,这样您就可以继续向受保护的resourceServer发出请求。这里的优点是,用户不必每次都提供凭据,因此用户的用户名和密码不容易被泄露。refresh_token的另一个主要用途是,假设您的authServer与现实世界中的resourceServer(第三方服务,如auth0、okta、azure等,或您自己的实现)相比非常受保护。您只需将access_token发送到resourceServer(以获取数据),而无需向resourceServer发送refresh_token。因此,当您的access_token发送到resourceServer时,很有可能会有黑客拦截您的resourceServer(因为它不像authServer那样安全),从而访问您的短暂访问权。因此,access_token的寿命很短(例如30分钟)。记住,当这个access_token过期时,您将向authServer(它比resourceServer更安全)发送refresh_token以获取新的access_toke。由于您在任何时候都不会向resourceServer发送refresh_token,因此拦截resourceServer的黑客不可能获得您的refresh_taken。如果作为一名开发人员,您仍然怀疑用户的refresh_token也可能被黑客入侵,那么您可以注销所有用户(使refresh_taken对所有用户无效),这样用户将再次登录(提供用户名和密码)以获得新的refresh_token+access_token,事情将再次步入正轨。

一些有用的资源

具有或不具有刷新令牌的工作流-Youtube

JWT认证代码示例-节点JS-Youtube

这一切都与扩展和保持资源服务器无状态有关。

您的服务器/资源服务器服务器是无状态的,这意味着不检查任何存储以快速响应。通过使用公钥验证令牌的签名来执行此操作。检查每个请求的access_token。通过只检查access_token的签名和过期日期,响应速度非常快,并允许扩展。access_token应该有很短的到期时间(几分钟),因为如果它被泄露,就没有办法撤销它。身份验证服务器/OAuth服务器服务器不是无状态的,但它可以,因为请求要少得多。仅在access_token过期时检查refresh_token。(例如每2分钟)请求速率远低于资源服务器。将刷新令牌存储在数据库中,并可以撤消它。refresh_token可能有很长的到期时间(几周/几个月),如果它被泄露,有办法撤销它。

不过有一个重要的注意事项,身份验证服务器的请求要少得多,因此可以处理负载,但是由于必须存储所有refresh_token,因此可能存在存储问题,如果用户急剧增加,这可能会成为一个问题。