简单地说,我们现在是Redis
有时候,人们会把原本只是为了解决一个小问题的技术应用到更广泛的领域。问题可能看起来相似,但使用独特的技术来解决一般问题可能会产生意想不到的后果。打个比方,如果你是一把锤子,那么一切看起来都像钉子。JWT就是这样一种技术。
有很多来自Okta等中小企业的深入文章和视频,讨论了使用JWT代币的潜在危险和低效[1].然而,这些警告被营销人员、youtube用户、博客作者、课程创建者和其他有意或无意地推广它的人所掩盖。
如果你看很多这样的视频和文章,你会发现它们都只是谈论JWT的好处,而忽略了不足之处。更具体地说,它们只是展示了如何使用它,但没有讨论JWT在实际生产环境中添加的撤销和其他复杂性。他们也从未将其与现有的久经考验的方法进行足够深入的比较,以真正衡量利弊。
又或许是它完美、吸引眼球、友好的名字让它如此受欢迎。“JSON”(通常很受欢迎)、“Web”(用于Web)和“Token”(意味着无状态)让人们认为它非常适合他们的Web身份验证工作。
所以我认为这是一个市场营销打败了工程师和安全专家的案例。但也不全是坏事,因为黑客新闻(Hacker News)上经常有关于智威汤逊的长时间而激烈的辩论在这里,她的e而且,在这里),所以还有希望。
如果你仔细想想,这些持续不断的争论本身应该是一个危险的信号,因为你不应该看到这样的争论,尤其是在安全领域。安全性应该是二进制的。技术要么安全,要么不安全。
无论如何,在这篇博客文章中,我想重点讨论使用JWT的潜在危险,并讨论一个已经存在了十年的久经考验的解决方案。
为了进一步理解,当我谈到JWT时,我指的是“无状态JWT”,这是JWT流行的主要原因,也是首先使用JWT的最大原因。另外,我在下面的参考资料部分列出了所有其他文章,这些文章对JWT进行了详细的介绍。
在我们理解为什么它是危险的之前,让我们先通过一个示例用例来理解它是如何工作的。
假设你正在使用Twitter。你登陆,写一条推文,就像一条推文,然后转发别人的推文。你做了四个动作。对于每个操作,您都需要经过身份验证和授权,然后才能执行特定的操作。
下面是传统方法的结果。
问题是,第四步很慢,需要在用户的每个动作中重复。因此,每个API调用都会导致至少两个缓慢的DB调用,这会降低整体响应时间。
有不同的方法来实现这一点。
现在让我们看看JWT的方法。
JWT,特别是作为会话使用时,试图通过完全消除数据库查找来解决这个问题。
其主要思想是将用户信息存储在会话令牌本身中!因此,与其使用一些长长的随机字符串,不如将实际的用户信息存储在会话令牌中。为了保护它,使用只有服务器知道的秘密签名令牌的一部分。
因此,即使客户端和服务器可以看到令牌的用户信息部分,但第二部分,即签名部分,只能由服务器验证。
在下面的图片中,令牌的粉色部分包含有效负载(用户信息),客户端或服务器都可以看到。
但是蓝色部分是使用一个秘密字符串、头部和有效负载本身签名的。因此,如果客户端篡改了有效负载(比如模拟了不同的用户),签名就会不同,不会进行身份验证。
下面是我们使用JWT时的用例:
接下来,对于每个用户操作,服务器只是验证签名部分,获取用户信息,并让用户执行该操作。因此完全跳过DB调用。
但是关于JWT令牌还有一件额外的重要事情需要了解。那就是它使用一个过期时间来让自己过期。通常设置为5到30分钟。因为它是自包含的,所以不能轻易地撤销/失效/更新它。这才是问题的症结所在。
JWT的最大问题是令牌失效问题。因为它会一直工作到过期,所以服务器没有简单的方法来撤销它。
下面是一些会使这种情况变得危险的用例。
想象一下你发完推特就退出了。您可能会认为您已经注销了服务器,但事实并非如此。因为JWT是独立的,它会一直工作到过期。这可能是5分钟或30分钟或任何被设置为令牌一部分的持续时间。因此,如果有人在此期间访问了那个令牌,他们可以继续访问它,直到它到期。
假设你是Twitter或一些在线实时游戏的管理员,而真正的用户正在使用该系统。作为版主,你希望迅速阻止某人滥用系统。你不能,同样的原因。即使在您阻止之后,用户仍将继续访问服务器,直到令牌过期。
假设用户是管理员,被降级为具有较少权限的普通用户。同样,这不会立即生效,用户将继续是管理员,直到令牌过期。
人们发现,多年来许多实现JWT的库都存在许多安全问题,甚至规范本身也存在安全问题。甚至是推广JWT的Auth0公司本身被一个问题击中.
在许多复杂的现实应用程序中,你可能需要存储大量不同的信息。而将其存储在JWT令牌中可能会超过允许的URL长度或cookie长度,从而导致问题。而且,您现在可能会在每个请求上发送大量数据。
在许多现实世界的应用程序中,服务器必须维护用户的IP并跟踪api以进行速率限制和IP白名单。所以无论如何,您都需要使用一个快速的数据库。认为使用JWT使应用程序变得无状态是不现实的。
一个流行的解决方案是在数据库中存储一个“已撤销令牌”列表,并为每次调用检查它。如果令牌是被撤销列表的一部分,那么阻止用户采取下一个行动。但是现在您正在对DB进行额外调用,以检查令牌是否被撤销,从而完全欺骗了JWT的目的。
尽管JWT确实消除了数据库查找,但在此过程中引入了安全问题和其他复杂性。安全性是二进制的——要么安全,要么不安全。因此,将JWT用于用户会话是很危险的。
在一些场景中,您在后台进行服务器到服务器(或微服务到微服务)通信,一个服务可以生成一个JWT令牌,将其发送到不同的服务以进行授权。在其中,您可以将JWT令牌作为一次性的短期令牌发送,以验证用户的电子邮件。
解决方案是完全不将JWT用于会话目的。相反,用传统的,经过实战检验的方法更有效。
例如,使数据库查找非常快(毫秒以下),额外的调用将不重要。
有没有这样的数据库,它能在亚毫秒内处理数百万个请求?
当然有。它被称为复述!成千上万的公司每天为数十亿用户提供服务,他们使用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)。
注意,闪电表情符号表示速度非常快。蜗牛表情符号表示速度很慢。
正如前面提到的,你也可以使用Redis作为整个数据层的主要数据库。在这种情况下,您的体系结构变得简单得多,基本上,一切都变得异常迅速。
当然,公司使用Redis不仅仅是作为一个独立的数据库,而是作为一个地理分布的数据库集群。