访问令牌和刷新令牌困境 - JWT

Posted

技术标签:

【中文标题】访问令牌和刷新令牌困境 - JWT【英文标题】:Access Token and Refresh Token Dilema - JWT 【发布时间】:2020-10-15 12:54:41 【问题描述】:

在使用 Access Token 和 Refresh Tokens 之后,我陷入了两难境地。

假设我们有以下场景:

    用户登录 -> 返回一个 访问令牌,有效期为 5 分钟,并保存在本地存储中。同时,一个刷新令牌有效期为3个月保存在cookies中,带有httpOnly安全属性。应用程序将使用访问令牌来访问资源,并在过期 5 分钟后自动使用刷新令牌生成新的访问令牌。 3 个月后,系统会要求用户再次登录。

    用户登录 -> 有效期为 3 个月访问令牌 保存在 cookies 中,带有 httpOnly 和 安全属性。应用程序将使用此令牌来访问资源,并在 3 个月后要求用户再次登录。

1方法代替2方法有什么意义?

【问题讨论】:

【参考方案1】:

什么都没有。如果你能做到#2,那么你应该这样做,而且更安全。 JWT 被过度使用,在 #2 的情况下,您的访问令牌几乎就像一个普通的旧会话 id,那么为什么不直接使用会话 id 呢? (唯一的原因可能是真正的无状态,但在许多情况下,应用程序无论如何都不是无状态的,例如,如果您希望能够撤销令牌。)

你不能用 #2 做的是将访问令牌发送到不同的来源,这有时是实际需要的。假设您的应用程序托管在 example.com 上,但您的 api 是 exampleapi.com。如果您将访问令牌存储在 cookie 中,则无法将其发送到 api。在更一般的情况下通常发生的情况是,您有一个刷新令牌(几乎像一个会话,但没有服务器端状态),身份提供者可以在 idp.example.com 上发布令牌,这是安全的域,htponly曲奇饼。这会发出一个 jwt,您从 www.example.com 下载的应用程序可以在 api.example.com 或其他任何地方使用,因为访问令牌是由 javascript 存储的(例如,在 localStorage 中)。关键是该令牌可以通过javascript(xss)访问,但它是短暂的,并且xss需要用户交互,因此攻击者在没有用户做某事的情况下发布新的访问令牌并不容易。刷新令牌更安全地存储在 httponly cookie 中。

如果您不想将令牌发送到不同的来源,那么 httponly cookie 实际上会更好,而且您是对的,那么刷新令牌没有多大意义。请注意,如果令牌存储在 cookie 中,您也必须缓解 csrf。

【讨论】:

好的,谢谢。这是有道理的。但是如果我们有另一个来源并且在登录时,我们会发送访问令牌和刷新令牌。我们将它们存放在哪里? 我不确定我是否理解这个问题。在单点登录场景中,发出访问令牌的登录服务器(身份提供者)应该在自己的域的 httponly cookie 中拥有自己的会话或刷新令牌,然后发出的令牌通常会存储在本地存储中,因此它可以用于应用程序域。如果没有单点登录,这整个事情没有多大意义,你只需要一个会话,或者一个长期存在的 jwt 存储在 httponly cookie(上面的#2),如果你接受 jwts 的风险,long会话,以及与此解决方案相关的额外复杂性。 好的,从你所说的我理解以下内容:用户登录 -> 刷新令牌保存在 Redis 中,假设为键:值对。访问令牌被发送到客户端,客户端将保存在本地存储中。如果访问令牌被盗,如何撤销刷新令牌? 为什么需要这些单独的令牌?为什么你真的需要代币?发出一个普通的旧会话 id 并在服务器端存储状态有什么问题,你的解决方案真的会有这样的负载,只有无状态的解决方案才能工作吗?即使在那种情况下,为什么不只是在登录时发出 jwt,将其作为 httponly cookie 发送给客户端,仅此而已?在您的情况下,刷新令牌的整个复杂性听起来没有必要。 我指的是你有不同来源的情况。

以上是关于访问令牌和刷新令牌困境 - JWT的主要内容,如果未能解决你的问题,请参考以下文章

JWT 刷新和访问令牌

JWT 访问令牌和刷新令牌安全性

JWT 是不是总是需要访问令牌和刷新令牌?

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

如何基于使用 Oauth2 协议的身份验证改进 JWT 访问令牌和刷新令牌?

在 Django REST 框架中使用 JWT 时,刷新令牌和访问令牌存储在哪里?