使用刷新令牌和访问令牌如何比仅使用 1 个 JWT 更“安全”?

Posted

技术标签:

【中文标题】使用刷新令牌和访问令牌如何比仅使用 1 个 JWT 更“安全”?【英文标题】:How can both using refresh- and access tokens be more 'secure' than just using 1 JWT? 【发布时间】:2020-11-17 04:18:35 【问题描述】:

与仅使用 1 个 JWT 令牌相比,同时拥有刷新令牌和访问令牌的系统如何“更安全”?

据我了解,在第一种情况下,如果刷新令牌有效,服务器将使用访问令牌进行响应(或者如果前一个尚未过期,则不响应)。在这种情况下,当中间人窃取访问令牌时,他们将有非常有限的时间来使用它(因为它们通常是短暂的)。

但是:如果中间人窃取了刷新令牌,只要刷新令牌有效,他仍然可以请求新的访问令牌。

因为通常刷新和访问令牌都存储在例如cookie 或本地存储;这个概念比仅使用 1 个过期时间更长的 JWT 更安全吗?

--

我可能在这里遗漏了一些非常简单的东西,但我就是无法理解它。除了能够控制“会话”,即刷新令牌有效性(因为它存储在内存/数据库中)之外,我没有看到这样做的好处。

【问题讨论】:

【参考方案1】:

您可能会感到困惑,因为您不需要整个 JWT。在您的场景中,一个普通的旧会话 id 可能就足够了,而且会更安全。 JWT 不是圣杯,并且被过度使用。

如果您以不同的方式存储它们,那么除了访问令牌之外还有一个刷新令牌才有意义。将它们都放在相同来源的 localStorage 中(几乎)没有意义,您可以只使用寿命更长的访问令牌,仅此而已。

但这不是重点。在这种情况下,您甚至不需要 JWT。

在一个典型的场景中,通常有一个身份提供者,如果你愿意的话,一个“登录服务器”会发布令牌。这与资源服务器(有时很容易被称为客户端)不同,资源服务器实际上是您的后端应用程序。发生的情况是您将未经身份验证的用户发送给身份提供者,例如 example-idp.com。他们在 example-idp.com 上进行身份验证(登录)并建立某种会话,例如通过在 example-idp.com 的 httpOnly cookie 中设置的刷新令牌。然后,您的用户将被重定向到您的应用程序,该应用程序直接接收访问令牌或某种可以交换访问令牌的代码。无论哪种方式,访问令牌都将为应用程序源存储,即。示例-app.com。这可以是一个 cookie,但它通常存储在 localStorage 中。原因是可能有多个应用程序(example-app1.com 和 example-app2.com),javascript 客户端必须向其发送相同的令牌,如果它存储在 httpOnly 中,则无法执行此操作cookie(尽管这对 XSS 是安全的)。

这样做的好处是,即使 example-app.com 被入侵(通过 XSS)并且攻击者破坏了一个短期访问令牌,他们仍然无法访问刷新令牌,因为这是设置的对于不同的来源,并且可能作为 httpOnly cookie。虽然访问令牌仍然有用,但 XSS 需要受害者用户交互(即用户必须做一些事情来运行攻击者的 javascript),因此一旦旧的过期,攻击者可能很难获得新的。

因此,简而言之,如果您没有所有这些复杂性,而只是拥有一个带有从同一来源下载的 javascript 客户端的普通服务器端应用程序,那么您不需要任何令牌或 JWT,最安全的选择是正确实现了普通的旧会话 ID。您可能会争辩说 JWT 是无状态的,但大多数应用程序根本不需要是无状态的(如果您需要令牌撤销,它也不能是无状态的)。如果您的应用确实需要无状态,并且您会以与访问令牌完全相同的方式存储刷新令牌,则您可以不使用刷新令牌 - 但请在设置到期之前评估风险。

您真正需要访问令牌的复杂性、通过刷新令牌更新等等通常是单点登录场景,或者如果您为不同的应用实现不同的存储(例如不同的来源,以及 httpOnly 与 javascript-accesible)令牌。

【讨论】:

这个很有见地。我检查的大多数来源都没有告诉/强调两个令牌都由不同的来源/服务器处理。在构建个人“爱好”项目时,仅使用 JWT 是一个不错的选择,因为它们本质上是无国籍的。在最坏的情况下,必须更改 JWT 机密以使所有令牌无效。如果我想以更好的方式控制它,最好像你说的那样坚持会话,因为存储令牌就像重新发明***(除非你选择刷新访问令牌组合)。【参考方案2】:

关于为什么两个令牌比一个更好,还有一点要说。

JWT 令牌不仅可以与一台服务器通信,而且可以与多台服务器通信。这种情况会成倍地增加攻击面,因为您与之交谈的每台服务器都具有暴露您的访问令牌并破坏您帐户安全性的相同潜力。这不仅仅是客户端安全的问题,无论您是否将两个令牌保存在本地存储中。服务器还需要得到保护,并且短期访问令牌可以降低风险,例如通过服务器上错误配置的日志处理暴露您的访问令牌。

将访问令牌视为脏令牌或用于完成任务的令牌。刷新令牌是一个干净的令牌。令牌仅在需要与身份验证服务器通信时使用。

【讨论】:

以上是关于使用刷新令牌和访问令牌如何比仅使用 1 个 JWT 更“安全”?的主要内容,如果未能解决你的问题,请参考以下文章

如何以管理员用户身份撤销用户的访问令牌和刷新令牌?在 Oauth2 中使用 JWT

如何使用 JWT 刷新令牌生成新的访问令牌

使用 JWT 刷新令牌如何安全?

如何在 Django 的单个 API 中获取访问令牌和刷新令牌(rest_framework_jwt)

Cognito 用户池:如何使用刷新令牌刷新访问令牌

过期后使用刷新令牌获取访问令牌(JWT)