稍后我会回答你的问题,现在先讨论一下刷新令牌的整个目的。
情况如下:
用户打开应用并提供登录凭据。现在,应用程序很可能正在与REST后端服务进行交互。REST是无状态的,没有一种方法来授权访问APIs。因此,在讨论中到目前为止,没有办法检查授权用户正在访问APIs还是只是一些随机请求。
现在为了能够解决这个问题,我们需要一种方法来知道请求是否来自授权用户。所以,我们引入了一个叫做访问令牌的东西来解决这个问题。现在,一旦用户成功验证身份,就会发放一个访问令牌。该令牌应该是一个长且高度随机的令牌(以确保它不能被猜测)。这就是JWT的作用所在。现在您可能希望在JWT令牌中存储任何用户特定的详细信息,也可能不希望这样做。理想情况下,您只想在JWT中存储非常简单、极其不敏感的详细信息。 JWT库本身会处理JWT哈希的操纵以检索其他用户的详细信息(IDOR等)。
因此,我们现在解决了关于授权访问的问题。
现在我们讨论攻击场景。假设使用上述所有内容,用户Alice通过应用程序获得了授权的访问令牌,现在她的应用程序可以根据自己的授权向所有API发出请求并检索数据。假设Alice“某种方式”失去了访问令牌,或者换句话说,入侵者Bob获得了访问Alice访问令牌的权限。现在,尽管未经授权,Bob也可以向Alice被授权的所有APIs发出请求。
我们理想情况下不希望发生这种事情。
解决这个问题的方法是:
1. 检测此类事件是否正在发生。
2. 缩短攻击窗口本身。
仅使用访问令牌很难实现以上第一种条件,因为无论是Alice还是Bob,都使用相同的授权令牌,因此两个用户的请求是无法区分的。
因此,我们尝试实现上述第二种条件,因此将有效期限添加到访问令牌的有效性中,例如,访问令牌在“t”(短暂)时间内有效。
它如何有助于?即使Bob拥有访问令牌,他也只能在有效期内使用它。一旦它过期,他就必须再次获取它。现在,当然,您可以说他可以用与第一次获得它相同的方式再次获得它。但是又有什么东西是100%安全的呢!
上述方法仍然存在一个问题,在某些情况下是无法接受的。当访问令牌过期时,需要用户重新输入登录凭据并再次获取授权访问令牌,这至少在移动应用程序的情况下是不好的(不可接受的)用户体验。
解决方案:这就是刷新令牌的作用。它是一个随机且不可预测的令牌,与访问令牌一起首次发放给应用程序。该刷新令牌是一个非常长期的特殊令牌,确保在访问令牌过期后立即向服务器请求新的访问令牌,从而无需用户重新输入登录凭据以检索新的已授权访问令牌,一旦现有的访问令牌过期。
现在您可能会问,Bob也可以访问刷新令牌,就像他损害了访问令牌一样。是的,他可以。但是,现在很容易识别此类情况,这在只使用访问令牌的情况下是不可能的,并采取必要措施减少造成的损害。
如何实现?
对于每个经过身份验证的用户(通常是移动应用程序),都会向应用程序发放一对一映射的刷新令牌和访问令牌。因此,在任何时候,对于单个经过身份验证的用户,将只有一个与刷新令牌对应的访问令牌。现在假设Bob已经破坏了刷新令牌,他会使用它生成访问令牌(因为只有访问令牌才被授权通过API访问资源)。由于Alice的访问令牌仍然有效,当Bob(攻击者)使用新生成的访问令牌请求时,服务器将看到这是一个异常情况,因为对于单个刷新令牌,一次只能有一个已授权的访问令牌。识别出该异常,服务器将销毁有问题的刷新令牌以及其所有相关联的访问令牌。从而防止任何进一步访问,无论是真实的还是恶意的,以获取任何需要授权的资源。
用户Alice将需要再次使用她的凭据进行身份验证并获取有效的刷新和访问令牌。
当然,您仍然可以争辩说Bob可能再次获得刷新和访问令牌并重复上述整个故事,从而可能导致对实际的真正客户Alice进行拒绝服务攻击,但是没有什么像100%安全的东西。
作为良好的做法,刷新令牌应该具有到期时间,尽管非常长。