简单地说,我们现在是Redis

了解更多

JSON Web令牌(JWT)对用户会话是危险的——这里有一个解决方案

了解JSON Web令牌(JWT)虽然很流行,但为什么是危险的,并查看一种经过实战验证的解决方案。



回到博客

有时候,人们会把原本只是为了解决一个小问题的技术应用到更广泛的领域。问题可能看起来相似,但使用独特的技术来解决一般问题可能会产生意想不到的后果。打个比方,如果你是一把锤子,那么一切看起来都像钉子。JWT就是这样一种技术。

来源:“停止在会话中使用JWT”(参见下面的链接)。
会话
来源:“为什么jwt不利于身份验证”-兰德尔DeggesOkta的开发商倡议负责人。
没有默认的
来源:“JWT不应该是您会话的默认设置”(参见下面的链接)。
“

有很多来自Okta等中小企业的深入文章和视频,讨论了使用JWT代币的潜在危险和低效[1].然而,这些警告被营销人员、youtube用户、博客作者、课程创建者和其他有意或无意地推广它的人所掩盖。

如果你看很多这样的视频和文章,你会发现它们都只是谈论JWT的好处,而忽略了不足之处。更具体地说,它们只是展示了如何使用它,但没有讨论JWT在实际生产环境中添加的撤销和其他复杂性。他们也从未将其与现有的久经考验的方法进行足够深入的比较,以真正衡量利弊。

又或许是它完美、吸引眼球、友好的名字让它如此受欢迎。“JSON”(通常很受欢迎)、“Web”(用于Web)和“Token”(意味着无状态)让人们认为它非常适合他们的Web身份验证工作。

所以我认为这是一个市场营销打败了工程师和安全专家的案例。但也不全是坏事,因为黑客新闻(Hacker News)上经常有关于智威汤逊的长时间而激烈的辩论在这里她的e而且,在这里),所以还有希望。

如果你仔细想想,这些持续不断的争论本身应该是一个危险的信号,因为你不应该看到这样的争论,尤其是在安全领域。安全性应该是二进制的。技术要么安全,要么不安全。

无论如何,在这篇博客文章中,我想重点讨论使用JWT的潜在危险,并讨论一个已经存在了十年的久经考验的解决方案。

为了进一步理解,当我谈到JWT时,我指的是“无状态JWT”,这是JWT流行的主要原因,也是首先使用JWT的最大原因。另外,我在下面的参考资料部分列出了所有其他文章,这些文章对JWT进行了详细的介绍。

在我们理解为什么它是危险的之前,让我们先通过一个示例用例来理解它是如何工作的。

用例

假设你正在使用Twitter。你登陆,写一条推文,就像一条推文,然后转发别人的推文。你做了四个动作。对于每个操作,您都需要经过身份验证和授权,然后才能执行特定的操作。

下面是传统方法的结果。

传统的方法

  1. 你用你的用户名和密码登录:
    1. 服务器首先验证用户。
    2. 然后,服务器创建一个会话令牌,将该令牌和用户信息存储在某个数据库中。(注意:会话令牌是一个长且无法识别的字符串,也就是opaque字符串,看起来像这样:fsaf12312dfsdf364351312srw12312312dasd1et3423r)
  2. 然后,服务器将会话令牌发送给前端移动或web应用程序。
    1. 这个令牌然后存储在cookie或应用程序的本地存储中。
  3. 接下来,假设你写了一条推文并提交了它。然后,与你的tweet一起,你的应用还将发送会话令牌(通过cookie或头部),以便服务器可以识别你是谁。但是令牌只是一个随机字符串,那么服务器如何仅从会话令牌就知道您是谁呢?
  4. 当服务器接收到会话令牌时,它将不知道用户是谁,因此它将该令牌发送给数据库以从该令牌检索(4a)实际用户的信息(如userId)。
  5. 如果用户存在并且被允许做这个动作(例如发送一条tweet),服务器就会允许他们做这个动作。
  6. 最后,它告诉前端推文已经发送。
灰色2

传统方法的主要问题是

问题是,第四步很慢,需要在用户的每个动作中重复。因此,每个API调用都会导致至少两个缓慢的DB调用,这会降低整体响应时间。

有两种方法可以解决这个问题

  1. 以某种方式完全消除用户的数据库查找(即消除步骤4)。
  2. 让额外的数据库查找速度更快,这样额外的跳转就不重要了。

选项1:消除数据库查找(步骤4)

有不同的方法来实现这一点。

  1. 您可以将状态存储在服务器的内存中。但是当您进行扩展时,这将导致问题,因为此状态仅在特定的服务器上可用。
  2. 使用“粘性会话”。这里告诉负载均衡器,即使在扩展后,也要始终将流量导向特定的服务器。这同样会导致不同的可伸缩性问题,如果服务器下降(缩小),您将失去所有状态。
  3. 第三种选择是JWT。接下来我们将对此进行研究。

现在让我们看看JWT的方法。

智威汤逊的方式

JWT,特别是作为会话使用时,试图通过完全消除数据库查找来解决这个问题。

其主要思想是将用户信息存储在会话令牌本身中!因此,与其使用一些长长的随机字符串,不如将实际的用户信息存储在会话令牌中。为了保护它,使用只有服务器知道的秘密签名令牌的一部分。

因此,即使客户端和服务器可以看到令牌的用户信息部分,但第二部分,即签名部分,只能由服务器验证。

在下面的图片中,令牌的粉色部分包含有效负载(用户信息),客户端或服务器都可以看到。

但是蓝色部分是使用一个秘密字符串、头部和有效负载本身签名的。因此,如果客户端篡改了有效负载(比如模拟了不同的用户),签名就会不同,不会进行身份验证。

编码

下面是我们使用JWT时的用例:

  1. 你用你的用户名和密码登录:
    1. 服务器通过查询数据库对用户进行身份验证
    2. 服务器然后使用用户信息和秘密(不涉及DB)创建一个JWT会话令牌。
  2. 然后服务器将一个JWT令牌发送给前端应用程序。对于以后的活动,用户可以只发送JWT令牌来标识用户,而不是每次都登录。
    1. JWT令牌看起来像这样:
      .. .< header>.. .< header>.. .
  3. 接下来,假设你写了一条推文并提交了它。当你发送它时,连同你的Tweet文本,你的应用程序也会发送JWT令牌(通过cookie或头部),以便服务器可以识别你是谁。但是服务器如何仅从JWT令牌就知道您是谁呢?部分令牌已经包含了用户信息。
  4. 因此,当服务器接收到JWT令牌时,它使用秘密来验证签名的部分,并从有效负载部分获取用户信息。这样就消除了DB调用。
  5. 如果签名签出,就允许他们执行操作。
  6. 最后发送消息被保存的前端

接下来,对于每个用户操作,服务器只是验证签名部分,获取用户信息,并让用户执行该操作。因此完全跳过DB调用。

灰色1

令牌过期

但是关于JWT令牌还有一件额外的重要事情需要了解。那就是它使用一个过期时间来让自己过期。通常设置为5到30分钟。因为它是自包含的,所以不能轻易地撤销/失效/更新它。这才是问题的症结所在。

那么,为什么JWT对用户身份验证来说是危险的呢?

JWT的最大问题是令牌失效问题。因为它会一直工作到过期,所以服务器没有简单的方法来撤销它。

下面是一些会使这种情况变得危险的用例。

  1. 注销并不是真的注销你!

想象一下你发完推特就退出了。您可能会认为您已经注销了服务器,但事实并非如此。因为JWT是独立的,它会一直工作到过期。这可能是5分钟或30分钟或任何被设置为令牌一部分的持续时间。因此,如果有人在此期间访问了那个令牌,他们可以继续访问它,直到它到期。

  1. 阻止用户并不会立即阻止他们。

假设你是Twitter或一些在线实时游戏的管理员,而真正的用户正在使用该系统。作为版主,你希望迅速阻止某人滥用系统。你不能,同样的原因。即使在您阻止之后,用户仍将继续访问服务器,直到令牌过期。

  1. 可能有过时的数据

假设用户是管理员,被降级为具有较少权限的普通用户。同样,这不会立即生效,用户将继续是管理员,直到令牌过期。

  1. JWT通常没有加密,因此任何能够执行中间人攻击并嗅探JWT的人现在都拥有您的身份验证凭证。这样做更容易,因为MITM攻击只需要在服务器和客户机之间的连接上完成。

其他复杂性和考虑事项

库和规范问题:

人们发现,多年来许多实现JWT的库都存在许多安全问题,甚至规范本身也存在安全问题。甚至是推广JWT的Auth0公司本身被一个问题击中

令牌的长度:

在许多复杂的现实应用程序中,你可能需要存储大量不同的信息。而将其存储在JWT令牌中可能会超过允许的URL长度或cookie长度,从而导致问题。而且,您现在可能会在每个请求上发送大量数据。

状态无论如何都需要维护(对于速率限制、ip白名单等)。

在许多现实世界的应用程序中,服务器必须维护用户的IP并跟踪api以进行速率限制和IP白名单。所以无论如何,您都需要使用一个快速的数据库。认为使用JWT使应用程序变得无状态是不现实的。

建议解决方法

一个流行的解决方案是在数据库中存储一个“已撤销令牌”列表,并为每次调用检查它。如果令牌是被撤销列表的一部分,那么阻止用户采取下一个行动。但是现在您正在对DB进行额外调用,以检查令牌是否被撤销,从而完全欺骗了JWT的目的。

底线

尽管JWT确实消除了数据库查找,但在此过程中引入了安全问题和其他复杂性。安全性是二进制的——要么安全,要么不安全。因此,将JWT用于用户会话是很危险的。

我可以在哪里使用它?

在一些场景中,您在后台进行服务器到服务器(或微服务到微服务)通信,一个服务可以生成一个JWT令牌,将其发送到不同的服务以进行授权。在其中,您可以将JWT令牌作为一次性的短期令牌发送,以验证用户的电子邮件。

如果我不能使用JWT,我还能做什么?

解决方案是完全不将JWT用于会话目的。相反,用传统的,经过实战检验的方法更有效。

例如,使数据库查找非常快(毫秒以下),额外的调用将不重要。

选择2:让玩家快速查看游戏内容(游戏邦注:这是一个久经考验的解决方案)

有没有这样的数据库,它能在亚毫秒内处理数百万个请求?

当然有。它被称为复述!成千上万的公司每天为数十亿用户提供服务,他们使用Redis就是为了这个目的!

Redi万博体育彩s Enterprise是Redis OSS的增强版,提供99.999%的可用性,可以服务数万亿的请求。它可以作为免费软件在私有云上使用,也可以在排名万博电竞客服前三的云上使用。

更多的是什么?万博体育彩Redis Enterprise现在已经从仅仅是一个缓存或会话存储,发展成为一个成熟的多模型数据库生态系统模块与core Redis一起原生运行。例如,你可以用RedisJSON快10倍和市场领先者),本质上有一个实时的类似mongodb的数据库,或者使用RediSearch模块4 - 100 x更快),并实现实时全文搜索,如Algolia。

如果你只是简单地使用Redis作为会话存储和一些其他数据库作为主数据库,这就是你的架构看起来的样子。需要注意的一点是Redis Enterprise提供万博体育彩的四种类型的缓存: Cache-aside (Lazy-loading), Write-Behind (Write-Back), Write-Through和Read-replica,不像Redis OSS只提供一个(Cache-aside)。

注意,闪电表情符号表示速度非常快。蜗牛表情符号表示速度很慢。

会话JWT

正如前面提到的,你也可以使用Redis作为整个数据层的主要数据库。在这种情况下,您的体系结构变得简单得多,基本上,一切都变得异常迅速。

Db JWT

它的规模吗?

当然,公司使用Redis不仅仅是作为一个独立的数据库,而是作为一个地理分布的数据库集群。

[1]引用:

  1. 停止在会话中使用JWT
  2. JWT不应该是会话的默认值
  3. 为什么jwt不利于认证——Randall Degges (Okta开发关系主管)
  4. 停止在会话中使用JWT,第2部分:为什么您的解决方案不起作用
  5. Thomas H. Ptacek报道
  6. 我使用JSON Web Token的经验
  7. Web上的身份验证(会话、cookie、JWT、localStorage等)
  8. Thomas H. Ptacek的博客

Baidu