访问令牌和刷新令牌的最佳实践是什么?如何实现访问令牌和刷新令牌。

53
我正在制作SPA,并决定使用JWT进行身份验证/授权,我已经阅读了一些关于令牌与Cookie的博客。我知道Cookie授权是如何工作的,并且了解基本令牌授权的工作原理。问题是,我不知道刷新令牌在其中如何适用,因为在我看来,它可能会降低安全性。让我解释一下我的想法:
Cookie 授权方式: 当您通过用户名和密码对用户进行身份验证时,会创建与该用户关联的会话ID。并将其设置为Cookie,每次客户端调用您的服务器时,它都会发送该Cookie,服务器可以查找与之关联的用户在数据库或某些其他服务器端存储上。
这种方法容易受到 CSRF (跨站请求伪造) 的攻击。为了防止CSRF,您可以使用带有cookie的令牌。此外,服务器还需要不断查找存储以查看 Cookie 指向哪个用户。
Token 授权方式: 当您通过用户名和密码对用户进行身份验证时,会创建一个签名的令牌,其中包含过期日期、电子邮件地址或用户ID、角色等信息。出于安全考虑,令牌应具有较短的过期时间。令牌可以存储在任何地方,例如本地存储、会话存储、Cookie中等。我将使用本地存储或会话存储来防止 XSRF (跨站脚本) 攻击。
这种方法容易受到 XSS (跨站脚本) 的攻击,但您可以通过验证HTML输入来防止此类攻击。由于令牌的生命周期很短,当令牌过期时,用户必须重新登录。
访问令牌和刷新令牌: 因此,我想使用刷新令牌来避免用户需要不断登录。例如,在进行身份验证时,我会为用户提供访问令牌和刷新令牌。当用户的访问令牌过期时,用户可以使用刷新令牌获取新的访问令牌。
以下是我的困惑:
- 如果我将访问令牌存储在本地存储中,同时也将刷新令牌存储在本地存储中,那么我不认为它有任何用处。因为如果攻击者可以访问本地存储并获取访问令牌,则他也可以获取刷新令牌。因此,在这种情况下,为什么不使用长寿命的访问令牌? - 如果您将刷新令牌存储为Cookie,则该Cookie容易受到XSRF的攻击,然后攻击者可以获取新的访问令牌并使用它。此时,为什么不直接使用Cookie授权呢?因为您已经必须查找本地存储以获取刷新令牌,尽管这比使用纯Cookie授权发生的频率要少得多。 最佳实践是什么? 目前,我正在考虑使用以下方法:
- 访问令牌 (本地存储,生命周期短) - 刷新令牌 (Cookie,生命周期长) - 用于刷新令牌的令牌(用于防止XSRF,本地存储,一次性使用)
假设我的解决方案如下:
  +--------+                                           +---------------+
  |        |------------ Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<--------------- Access Token -------------|               |
  |        |               & Refresh Token (cookie)    |               |
  |        |               & XSRF Token                |               |
  |        |                                           |               |
  |        |                                           |               |
  |        |--------- Access Token ------------------->|               |
  |        |                                           |               |
  |        |<----- Protected Resource -----------------|               |
  | Client |                                           |     Server    |
  |        |--------- Access Token ------------------->|               |
  |        |                                           |               |
  |        |<----- Invalid Token Error ----------------|               |
  |        |                                           |               |
  |        |                                           |               |
  |        |---------------- Refresh Token ----------->|               |
  |        |               & XSRF Token                |               |
  |        |                                           |               |
  |        |<--------------- Access Token -------------|               |
  |        |               & XSRF Token                |               |
  +--------+               & Optional Refresh Token    +---------------+

每次使用刷新令牌后,服务器都会发出新的XSRF令牌(在使用一个XSRF令牌后,它将停止工作并且服务器会发出新的令牌)。

你对这种实现有什么看法?

在我看来,这限制了服务器对数据库的查询,因为它使用了访问令牌。访问令牌是短暂的,用户不必经常登录,因为它使用刷新令牌/cookie,而这些是由XSRF令牌保护的。

这样做可以吗?

谢谢!

1个回答

37

关于访问令牌和刷新令牌

把访问令牌看作是一种“脏”令牌。这种令牌需要共享很多次。你不必只在一个服务器上传递令牌,可以在多个服务器之间传递。因此攻击面增大了。如果某个服务器做出愚蠢的事情,例如将令牌写入服务器日志并将日志暴露给外界,你希望限制负面影响,因此访问令牌的生命周期短,以限制攻击者能够执行恶意操作的时间。

另一方面,刷新令牌是一种“干净”的令牌。你自己存储并且只在必要时使用它。当然,如果攻击者获得物理访问权限到你的计算机和用户代理,那么游戏就结束了。但在这里我们试图保护远程攻击者。刷新令牌应该只用于与授权服务器或授权终点谈话。如果你决定将其设置为cookie-可以-只需记住将目录路径限制为令牌要传递到的REST终点。

关于你的解决方案

从我的角度来看,它看起来不错。也许我不会实现XSRF令牌,只是为了节省精力。我的意思是,如果有人尝试通过CSRF攻击,最糟糕的事情是什么?他可能能够让你刷新你的令牌。但令牌不会因为CSRF而暴露给攻击者。

还有一件事

我喜欢你的问题。它写得非常好!:)


5
是否有这样一种架构设计,即客户端永远无法访问刷新令牌,并且请求新的访问令牌的过程全部在幕后完成(采用前端->后端->授权服务器架构,后端实现所有逻辑)。是否有人听说过这个想法? - manuelnucci
1
到目前为止,我找到的唯一解释真正解释了为什么需要有2个令牌。OAuth提供者的文档,甚至RFC都没有更好的解释。<br/> 对@manuelnucci的问题+1。我认为最安全的方法是将授权授予重定向到客户端后端,后者将重定向到客户端前端,并将访问令牌设置为httpOnly cookie。问题在于,采用这种方法,客户端后端将不得不处理其所有用户的令牌轮换,这将增加服务器负载。 - fires3as0n

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接