如何允许用户使用刷新令牌从多个设备进行连接?

信息安全 验证 api 令牌
2021-08-23 20:38:57

这个问题在我之前的一个问题之后:如何安全地让我的用户使用刷新令牌登录?

我从上一个问题中得到的是,我们需要:

  • 短期访问令牌
  • 长寿命的一次性刷新令牌

刷新令牌以 1-1 关系与用户一起保存在数据库中(1 个用户 = 1 个刷新令牌)。每次为用户创建刷新令牌时,它都会替换前一个用户的持久令牌(如果有)。这使得可能的黑客只有一个有限的窗口来做他们的事情:

  • 用户登录并接收访问令牌A1和刷新令牌R1
  • 黑客以某种方式获得了这些令牌
  • 访问令牌A1到期,因此黑客获得了新的访问/刷新令牌A2/R2由于被盗的刷新令牌R1:新创建的刷新令牌R2(只有黑客拥有)替换了R1数据库中的前一个(用户拥有的)
  • 用户未能获得新的访问令牌,因为他的刷新令牌R1不再存在,因此再次登录并获得新的访问/刷新令牌A3/ R3:新创建R3的刷新令牌(只有用户拥有)替换R2DB 中的前一个(黑客的那个)拥有)
  • 黑客的access tokenA2过期了,但是因为refresh token已经不存在,拿不到新的了R2:需要再次窃取token(当然应该很难)

我在这里想知道的是,如何允许用户使用这种机制从多个设备进行连接?例如,如果用户使用两台不同的笔记本电脑登录,那么刷新令牌将始终相互擦除......有什么线索吗?

2个回答

在我看来,您现在提出的问题不再是关于安全性,而是更侧重于概念的实施。您已经确定刷新令牌会使攻击者更难攻击,并且看起来您有一个有效的实现。根据您的描述,您正在使用自定义解决方案,而不是像 OAuth2 库实现那样为您提供此功能。

您现在需要决定是否要从同一个用户帐户进行多个设备身份验证。如果您不希望用户使用一个帐户从多台设备登录,那么恭喜,您的解决方案已经奏效。他们将很快从旧设备中注销,因为它在超时后将不包含正确的刷新令牌。

如果您确实希望让用户能够在同一帐户上从多个设备登录,那么很遗憾,您需要进行一些更改。一种可能的解决方案是在您的数据库中添加一个设备标识字段并为每个设备发出一个刷新令牌。

我同意乔的回答

一种可能的解决方案是在您的数据库中添加一个设备标识字段并为每个设备发出一个刷新令牌。

但我想添加一些实现细节。

IMO 最强大和功能最强大的解决方案是:每个用户在数据库中有许多记录,每个记录有两列:refresh_token 和 device_id。

让我们检查主要情况:

  • 用户登录当然,他是在密码的帮助下做到的。他传递了 device_id (实际上是任何唯一的数字)。如果密码正确,服务器生成新的访问和刷新令牌,将 access_token 发送给客户端,并将 refresh_token 和 device_id 插入数据库。
  • 用户消费服务. 他发送 access_token(女巫内部必须对用户信息进行编码,显然(例如他的登录名)和到期日期)。服务器检查令牌(在其秘密签名密钥的帮助下)以确保该令牌是真实的而不是假的。服务器还检查 access_token 到期日期。如果过期,用户必须在适当的 refresh_token 和(重要的!)device_id 的帮助下刷新它。如果数据库中的 refresh_token 不等于用户的令牌,那么我们就会被黑客入侵。但不要惊慌——我们只是删除刷新令牌并将用户重定向到登录页面!就是这样,只要 access_token 还活着,黑客就可以访问(像往常一样短时间)!如果您需要即时访问阻止,您可以将 access_token 与 refresh_token 一起存储在 db 中,并且还有一个内存中的 access_tokens 黑名单。
  • 用户注销。他从 cookie/localstorage 中删除了他的 access_token,将 refresh_token 和 device_id 发送到服务器,服务器将它们从列表中删除。(我们不想收集过时的未使用令牌)
  • 用户更改密码。服务器删除所有以前的 refresh_tokens。如果您使用令牌黑名单 - 将所有当前用户的 access_tokens 添加到其中。有了这样的解决方案,实现“从所有设备注销”功能也很容易。
  • 黑客窃取 access_token 并且用户不知道它黑客只能使用它直到它过期(短时间框架)。
  • 黑客还窃取了 refresh_token 并制作了 refresh用户将无法使用他的旧 refresh_token,在这种情况下他会提示再次登录,新的刷新和访问令牌将生成,黑客失去访问权限。(见案例#2)

您应该清楚了解的一件事:刷新令牌只能在黑​​客窃取访问/刷新令牌而不是真实密码的情况下拯救您!因为如果他得到了通行证,那么你就有麻烦了,你必须实现恢复密码的协议(例如,借助电子邮件或短信)

PS 拥有可以过期的 refresh_token 是个好主意。为防止出现这种情况,当jacker 从旧设备窃取访问权和刷新令牌时,该设备现在从未使用过。

PPS 最好有定期的数据库任务来清理过期的 refresh_token 行(也许你必须为此添加列 refresh_token_expiration_date)

PPPS 我不是安全专家,所以如果您认为有更好的解决方案,我很乐意进行讨论。

感谢阅读,希望对你有帮助)