为啥我们不应该使用 access_token 作为 refresh_token

Posted

技术标签:

【中文标题】为啥我们不应该使用 access_token 作为 refresh_token【英文标题】:why shouldn't we use the access_token as the refresh_token为什么我们不应该使用 access_token 作为 refresh_token 【发布时间】:2018-01-15 02:24:41 【问题描述】:

我了解使用访问/刷新令牌的身份验证过程如下:

    为 refresh_token 交换用户名/密码 使用 refresh_token 获取 access_token 将 access_token 用于请求(无需 DB 调用) 如果 access_token 已过期 -> 使用 refresh_token 获取新的(需要 DB 调用)

管理/撤销访问的流程:

    为 refresh_token 交换用户名/密码 将 refresh_token 存储在数据库中 使用 refresh_token 获取 access_token 时检查 DB 中的已撤销标志 通过设置撤销标志来阻止

数据库交互: 只需要刷新令牌。即频率取决于 access_token 的生命周期。

用户体验:

时需要登录 第一次访问 refresh_token 已撤销 refresh_token 已过期

安全隐患:

refresh_token 被盗:在手动撤销之前或很长一段时间内易受攻击 access_token 被盗:短时间内易受攻击。无法撤销 注销:access_token 一直有效,直到过期/无法撤销

没有 refresh_token: +没有长期存在的漏洞 -糟糕的用户体验。用户需要经常登录

现在我想知道为什么我们不能只使用 access_token 作为 refresh_token:

    为 access_token 交换用户名/密码 将 access_token 存储在数据库中 对所有请求使用 access_token(无 DB 调用) 过期时:检查 DB 是否设置了撤销标志。如果不是 -> 创建新的 access_token 并为旧令牌设置撤销。 (可选,仅 到期后允许此 x 次。这相当于一个 refresh_token 的到期日期)

现在 UX/security/DB_call_frequency 似乎是相同的。那么为什么我们需要一个单独的 refresh_token 呢?

我能看到的唯一论点是,将它们分开可以降低 refresh_token 被盗的风险,因为它发送的频率较低。

【问题讨论】:

【参考方案1】:

创建新的 access_token 并为旧令牌设置撤销。 (可选地, 到期后仅允许此操作 x 次。这相当于 refresh_token 的到期日期)

您想通过交换用户名和密码再次执行此操作吗?

如果是这样,那么用户需要再次登录。您可以使用客户端凭据授予https://www.rfc-editor.org/rfc/rfc6749#section-4.4 或隐式流https://www.rfc-editor.org/rfc/rfc6749#section-4.2 仅发送访问令牌,这些流不发送刷新令牌。如果您可以发送用户名和密码,则可以在每次过期时使用客户端凭据授予和请求访问令牌。

【讨论】:

不,我不是故意使用用户名/密码。过期的 access_token 可以换成新的,除非它被撤销。所以access_token基本上也是refresh_token 旧的访问令牌过期后如何获得新的访问令牌?要获得新的,您需要再次进行身份验证。如果您不想发送用户名和密码来获取新令牌,则需要使用刷新令牌方法。如果我理解正确,请告诉我。 系统应该允许刷新一个 access_token,即使它已经过期(可选的硬限制为例如 1 周)。为了安全起见,它应该在刷新之前检查令牌是否已被列入黑名单。所以它与用于 refresh_tokens 的过程基本相同,但它使用(过期的)access_token 而不是单独的 refresh_token 这是一种 OAUTH 方法吗?我不认为 OAuth 有这种方法。您使用的是哪种 OAuth?Google Microsoft? 不,它只是一个 JWT 令牌。不是完整的 oauth 工作流程

以上是关于为啥我们不应该使用 access_token 作为 refresh_token的主要内容,如果未能解决你的问题,请参考以下文章

为啥不应该使用 Number 作为构造函数? [复制]

为啥我不应该在 IDP 上下文中使用 IdToken 作为不记名令牌?

为啥我们不应该将每个包含的 Android XML 布局包装在一个 <merge> 对中?

「DevOps系列]为啥我们使用Terraform 而不使用Puppet, Ansible

为啥我要传输 `client_secret` 来获取 `access_token`?

为啥我们不应该在 javascript 中使用 ++? [复制]