如何使用JWT刷新令牌和短暂的访问令牌而不是大规模不安全?

时间:2016-08-28 11:15:19

标签: security jwt

据我了解,JWT刷新令牌的典型(和简化)用法如下:

  1. 用户登录系统。向用户授予刷新令牌和短期(例如:10分钟到期)访问令牌。刷新令牌存储在"认证服务器"的数据库中。用于撤销目的。对应用程序发出的任何请求("资源服务器")都将使用短期访问令牌。
  2. 当用户的10分钟结束时,客户端将使用刷新令牌向auth服务器发送请求以获取新的访问令牌。
  3. 当用户更改其密码或撤消对特定登录的访问时(在被盗,丢失设备等情况下),刷新令牌将从auth服务器数据库中删除并使其无效。
  4. 因此,当用户意外泄露其密码或丢失其设备时,他只需更改其密码,这将导致所有先前发布的刷新令牌失效。

    然而,这里明显的安全漏洞是短暂的访问令牌在接下来的10分钟内仍然完全有效。 10分钟,无论多短时间,仍然有足够的时间让恶意用户造成一些损害。

    我能想到的唯一可行解决方案是:

    • 维护访问令牌的黑名单或白名单。这使得 刷新令牌的使用似乎很多余。如果我们要打 每个请求上的数据库或保留列入黑名单的缓存列表 访问令牌,那么拥有刷新令牌的重点是什么?

    • 缩短访问令牌的到期时间(例如:每1分钟一次) 而不是每10分钟)。这并不能解决问题 只是做一些损害控制,因为它缩短了时间窗口a 恶意用户必须造成伤害。并打造一个新的数据库 每分钟访问令牌并不比击中令牌好得多 每个请求都有数据库。

2 个答案:

答案 0 :(得分:2)

我一直在研究完全相同的问题。虽然我不能说我对这个问题有任何明确的权威,但我很高兴根据大量的研究和建立概念证明来分享我的想法。

要求是使用即时令牌访问令牌撤销。在应用程序的常规操作期间,恶意用户访问某人帐户的场景的实际概率相对较低。这并不是说它不应该被考虑在内,但是99.9%的请求进入你的系统并不会是这种情况,因此它会在所有请求中检查对数据库的访问令牌。在我看来,事情是糟糕的设计。

然而,不好的设计与否,它不会改变要求。要求访问令牌每分钟刷新一次似乎并没有好多,因为它会给auth服务器和数据库带来巨大压力。管理内存访问令牌撤销列表不会有多大好处,因为它不会跨实例共享。根据您的用户数量,这可能会在一段时间内使用数据库,但我认为它不会超出某一点。

我选择使用的解决方案是使用共享的内存数据库/缓存。我已经评估了Cassandra,Redis和Apache Ignite,并且暂时决定使用Ignite。因为我不确定它一旦投入生产后会如何执行,我已经让组件可以轻松地替换为内存解决方案,以防性能不足。

我有一个JWT过滤器负责验证每个请求,最后我调用共享缓存来检查访问令牌撤销列表。我预计绝大部分时间列表都是空的。为了进一步降低潜在的性能下降,我在使用MD5之前将令牌哈希到大约40个字符,然后再撤销它们。这个功能允许我有一个小时的访问令牌寿命和一个18小时的刷新令牌,而不用担心如果需要,我将无法删除恶意用户。

就个人而言,我没有看到在后端跟踪某些用户状态的方法。诀窍是以这样的方式完成,即您仍然可以轻松添加后端实例以扩展应用程序。

答案 1 :(得分:2)

JWT代币的目的是它们是独立的并且可以在短时间内独立生存。如果这不符合您的要求,您可以恢复到另一种类型的访问令牌,即在授权服务器(AS)中需要所谓内省的不透明令牌。你是对的(如果没有缓存该调用的结果)该调用每次都会命中AS并且部分地破坏刷新令牌的目的但另一方面,主动不得不撤销每个资源服务器的缓存访问令牌结果已经进行了内省调用将导致管理和头顶上的噩梦。

没有银弹。您必须选择最符合您安全要求的访问令牌类型,到期时间和缓存持续时间。