JWT访问令牌和刷新令牌流程

3

以下是我的认证流程:

  1. 用户登录后会收到两个令牌(access token具有过期时间,refresh token无过期时间)
  2. 对于每个用户,refresh token都将存储在数据库中的JSON列refreshTokens中(该列为数组)。
  3. 在客户端上,access token和refresh token都存储在本地存储中。
  4. 当需要验证用户时,如果access token已过期,则使用refresh token创建一个新的access token,并将其发送回用户,使用户继续保持登录状态。
  5. 当用户退出时,从数据库中删除存储在refreshTokens列表中的refresh token。

我的问题如下:

  1. 这个流程是否安全?
  2. 我需要将refresh token保存在cookie中,还是只用本地存储就足够了?
答案:
1. 这个流程看起来是相对安全的,因为它使用了access token和refresh token的组合,加上过期时间和数据库中的存储方式可以帮助减少攻击风险。但要确保刷新token时进行必要的身份验证,并限制refresh token的范围以保护用户账户。
2. 将refresh token保存在cookie中或本地存储中都可以,但是请注意,将敏感信息保存在cookie中可能会被跨站点请求伪造(CSRF)攻击利用,因此请确保采取必要的安全措施来保护cookie。

为了使其更加安全,我确保刷新令牌与“设备”相关联 - 在移动应用程序中,使用手机ID很容易,在浏览器上,这可能会更具挑战性 - 例如UA和地理/ IP的组合。 - noitse
4个回答

2
那种流程是根据OAuth的工作方式和如何以安全的方式存储令牌,所以两个问题都是"是"。缺失的部分是如何首先获取令牌:为此,使用PCKE的授权码授权类型比传统的隐式授权类型更受欢迎。请注意保留HTML标签。

2
这个流程的重要安全措施是,在第4步中使用数据库中保存的刷新令牌列表来验证RT未被撤销。除此之外,看起来还不错。您可以通过为刷新令牌添加过期时间来增加安全性。然后,即使用户没有主动注销(您没有从数据库中清除RT),在一段时间后也无法使用RT。

在本地存储令牌在我看来已经足够好了。


我最近为每个刷新令牌添加了一年的过期时间和每个访问令牌添加了10分钟的过期时间。但是你说我不需要在数据库中保存刷新令牌?那我应该把它们放在哪里?Redis存储可能吗? - saeid ebrahimi
1
不,我的意思是:你可以将RT保存在数据库中,这是可以的。因此,当您收到刷新请求时,请确保不仅验证RT的签名(如果它是JWT),还要将接收到的RT与您在数据库中拥有的列表进行比较。只有这样,您的解决方案才是安全的。 - Michal Trojanowski
您还可以使用短期RT(例如4小时/1天等),每次用户刷新AT时,您都会延长RT(发出新的RT)。这样,您就不必将它们保存在数据库中,并且您知道如果用户在RT的过期时间内使用您的网站,他们将被“注销”(因为如果用户在那一天内没有做任何事情,RT将变为过期)。 - Michal Trojanowski
1
我所做的是创建一个访问令牌(有效期为10分钟)和一个刷新令牌(有效期为6个月),当我验证刷新令牌时(假设访问已过期),首先我会验证签名,然后与数据库中的refreshTokens列表进行比较。 - saeid ebrahimi

1
阅读此文时,我脑海中浮现出一些想法:
1. 刷新令牌也需要过期时间。事实上,我认为刷新令牌就像是一把双刃剑。想象一下这样的情况:一个人获取了刷新令牌的访问权限,他不仅可以访问资源,而且还可以在资源上获得更多的时间。当使用刷新令牌重新生成访问令牌时,我更喜欢重新生成刷新令牌,并设置其过期时间。
2. 将刷新令牌存储在数据库中很酷。然而,我有一个替代方案,你可以轻松地使用RSA算法,然后使用私钥生成令牌并使用公钥进行验证。这可以减少需要存储刷新令牌的情况。
3. 在客户端,我强烈反对使用本地存储。我更喜欢使用HttpOnly Cookies,并将标志设置为true。HttpOnly Cookies不会在JS中呈现,并根据Http协议安全地发送到服务器。这可以修复令牌被攻击的风险。
总体来说,你的REST概念已经足够好了。

0

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