JWT 刷新令牌的全部意义是什么?

Ger*_*áth 28 security authentication access-token jwt refresh-token

我已经读了一段时间了,没有任何意义,而且解释相互矛盾,评论证明了这一点。

到目前为止,我的理解是 JWT 存储由服务器编码的信息,可以有过期时间,并且服务器及其密钥可以解码其中的信息(如果它有效)。说得通。

它对于可扩展性很有用,因此独立的 API 可以解码并验证令牌中的信息,只要它们拥有密钥。此外,不需要将信息存储在任何数据库中,这与会话不同。说得通。

如果令牌被盗,API 无法判断令牌是否由正确的人使用。这是上面的缺点。

通过减少令牌的过期时间,可以减少安全漏洞,从而减少窃贼未经许可使用令牌的时间。(附带问题,但如果他们能够偷一次,他们可能也会偷第二次)

但是减少令牌的有效时间意味着每次令牌过期时用户都需要登录,并且如上所述,这种情况相当频繁,因此不会提供太好的用户体验。说得通。

从现在开始,一切都没有意义了:

引入刷新令牌可以解决这个问题,因为它的过期时间更长。使用刷新令牌可以生成访问令牌,因此只要用户拥有刷新令牌(时间较长)就可以登录,而被盗的访问令牌仍然仅在短时间内有效。

对我来说,上述内容似乎增加了一层额外的复杂性,而安全性没有任何改进。即对我来说,上面的内容似乎等于一个长期存在的访问令牌。

为什么?因为对我来说,刷新令牌基本上是一个访问令牌(因为这就是它生成的)。因此,拥有刷新令牌意味着无限制的访问令牌,因此无限制地访问 API。

然后我读到一个答案,刷新令牌和访问令牌是一对一的映射,因此窃取访问令牌仍然意味着对 API 的未经授权的访问,但只持续很短的时间,并且窃取刷新令牌将生成不同的访问令牌,以便 API 可以检测到异常(同一帐户使用不同的访问令牌),从而使访问令牌失效。

看来我不是唯一一个对这个问题感到困惑的人。

如果上述情况不正确,刷新令牌有何真正帮助?

如果上述情况成立,并且确实存在刷新令牌和访问令牌的一对一映射:

  • 它完全失去了“无国籍”的好处
  • 用户无法从多个设备登录(这将是“异常”)
  • 我无法理解访问令牌如何失效 - 令牌数据中是否存储了会话 ID,或者用户被“阻止”?

如果有人能澄清这个问题那就太好了,因为从 5 个解释中,有 5 个相互冲突的陈述(有时相同的解释包含冲突的信息),并且许多开发人员都想了解这种方法。

Gab*_*yel 14

基于令牌的身份验证存在普遍的混乱,因此让我们尝试澄清其中一些问题。

首先,JWT 不仅由服务器“编码”,而且还“签名”(更准确地说,通常是消息身份验证)。目的是这样的令牌不能被客户端或任何人更改或改变,因此令牌中的任何字段(声明)都可以被信任为发行者创建它的样子,否则验证将失败。

这产生了两个重要的结论:

  • 验证令牌在任何实现中都很重要(显然)
  • JWT 的内容(声明)未加密,即 这不是秘密,客户可以查看

如果这样的令牌包含主题的某种身份(用户,如用户 ID 或电子邮件地址)和过期时间,则可以使用它来维护没有服务器端状态的会话。

另一个重要的收获是:

  • 注销(立即会话失效)不可能以无状态方式实现,这是一个缺点。为了能够注销以使现有会话无效,服务器必须存储并检查已撤销的令牌,这必然是有状态操作。

此外,JWT 令牌通常以客户端代码 (javascript) 可以访问的方式存储,因此客户端应用程序可以读取用户是谁以及令牌何时过期等信息。不一定如此,但大多数实现都是这样做的,例如。将其存储在本地存储中。这使得这些令牌容易受到 XSS 攻击,这意味着任何成功的 XSS 都将能够获取令牌。

由于到目前为止讨论的原因,JWT 身份验证本质上不如普通的旧会话安全,只有在需要时才应使用。很多时候,当使用令牌身份验证时,实际上并不是必需的,只是一种幻想。

有时,这样的令牌存储在 httpOnly cookie 中,但在这种情况下,令牌不能发送到多个源(localStorage 的一个好处),并且也可以使用普通的旧会话 ID,并且实际上会更安全。

好的,那么什么是刷新令牌。正如您正确指出的那样,限制访问令牌的生命周期对于限制受损令牌的有效性很有用。因此,当旧的访问令牌过期时,可以使用刷新令牌来获取新的访问令牌。关键是这些存储在哪里。

一个关键要点:

  • 如果刷新令牌的存储方式与访问令牌相同,则通常没有任何意义。这是实施中的常见错误。

在更好的架构中,可能会发生以下情况:

  • 至少有两个独立的组件(逻辑上和“物理上”,这在当今的云世界中有意义):身份提供者(IdP,或“登录服务”)和资源服务器(例如 API)。
  • 当用户登录时,他们实际上创建了与 IdP 的会话。在这种情况下,将为 IdP 源(域名)设置普通的旧会话 ID(充当刷新令牌)或实际的 JWT 刷新令牌。
  • 然后,当资源服务器源需要时,使用与身份提供者的现有会话创建访问令牌。
  • 现在,即使资源服务器完全受到攻击,例如成功的 XSS,刷新令牌也属于完全独立的来源,因此攻击者无法访问。即使它是同源的,但刷新令牌位于 httpOnly cookie 中,这也会有所帮助,因为攻击者随后需要能够针对受害者用户执行重复的 XSS 以接收新的访问令牌。

可以有这样的实现变体,但要点是上面的,对两个令牌的访问的分离。

正如您所描述的,刷新令牌到访问令牌的一对一映射是不寻常的,也是不必要的,但实际上有时每个用户一个会话是必需的(特别是在您想要进行非常清晰的审计的金融应用程序中)用户所做的事情的踪迹)。但这和上面讨论的事情没有太大关系。

同样如上所述,以无状态方式正确注销(会话失效)是不可能的。幸运的是,很少有应用程序实际上需要在服务器端实现真正的无状态。

  • 对于该用例,普通的旧会话也更简单、更安全。当您需要 SSO、不同于资源服务器的身份服务器或多个资源服务器时,令牌就可以发挥作用。对于更简单的场景,您通常不需要 JWT。 (2认同)
  • @ThabetSabha 谁是攻击者?假设这是另一个人(第 3 方),那么他们将不会与身份提供商 (IdP) 建立有效的会话,即。他们将无法访问刷新令牌 - 这就是重点,这就是为什么您需要以不同的方式存储它。这意味着不会颁发新的访问令牌。换句话说,访问令牌用于服务本身,而刷新令牌用于身份提供者,后者将存储在不同的源中,可能存储在 httponly cookie 中,因此更难获取。 (2认同)
  • @ThabetSabha 我怀疑您可能一直在想的是攻击者执行 XSS 不仅是为了获取访问令牌,而且还为了利用刷新令牌。但这是行不通的,因为刷新令牌不应该在服务源上访问(由于 httpOnly),并且身份提供者不应该容易受到 CSRF 的攻击,因此无法制作这样的请求。 (2认同)
  • 此外,即使这是可能的,也需要进一步的用户交互,攻击者自己无法做到这一点,这增加了一些薄层的保护。(XSS 在用户上下文中可能不太容易被利用,他们实际上需要做一些事情,这限制了攻击者的机会,而不是没有刷新令牌并获得对寿命更长的访问令牌的访问权限。) (2认同)