有时,人们采取旨在解决狭隘问题的技术,并开始广泛应用。问题可能看起来类似,但利用独特的技术来解决一般问题可能会产生意外的后果。使用隐喻,如果你是锤子,一切都看起来像钉子。 JWT是一种这样的技术。
像OKTA这样的公司中小企业有许多深入的文章和视频谈论使用JWT令牌的潜在危险和效率低下[1]。然而,这些警告被营销人员,YouTubers,博主,课程创作者和其他人故意或不知不觉推广它的人黯然失色。
如果您查看许多这些视频和文章,他们只是谈论JWT的感知益处,忽略了缺陷。更具体地说,他们只是展示了如何使用它,但不要谈论JWT在实际生产环境中增加的撤销和额外的复杂性。他们也从未将其与现有的战斗方法进行比较,足以真正权衡利弊。
或者也许这是一个完美的,无法友好的名称,这导致其受欢迎程度。 “JSON”(通常很好),“Web”(对于Web)和“令牌”(意味着无状态)让人们认为它是完美的网络身份验证作业。
所以我认为这是营销击败工程师和安全专家的情况。但是,这并不糟糕,因为在黑客新闻上有常规长期和热情的辩论(见这里,她和这里),所以有希望。
如果您考虑过它,这些不断的辩论本身应该是一个红旗,因为你永远不应该看到这种辩论,特别是在安全领域。安全性应该是二进制的。无论是安全还是它都不是安全的。
无论如何,在这个博客文章中,我想专注于使用JWT的潜在危险,并谈论一段十年来的战斗测试解决方案。
为了进一步理解,当我谈论JWT时,我的意思是“无国运JWT”,这是JWTS普及的主要原因,最重要的是使用JWT的最大原因。此外,我已经列出了下面的资源部分中的所有其他文章,进入JWT的Nitty-Gritty。
在我们理解为什么它是危险之前,让我们首先通过采取示例用例来了解它的工作原理。
想象一下你正在使用推特。您登录,写一个推文,如推文,然后转发别人的推文。所以你做了四个动作。对于每个操作,您需要在执行该特定操作之前进行身份验证和授权。
您使用用户名和密码登录:服务器然后创建一个会话令牌,将该令牌存储在某些数据库中的用户的信息。 (注意:会话令牌是一个长期不明的字符串-AKA OPAQUE字符串 - 看起来像这样:FSAF12312DFSDF364351312SRW12312312DASD1ET3423R)
然后服务器将您的会话令牌发送到前端移动或Web应用程序。然后将该令牌存储在Cookie中或应用程序的本地存储中。
接下来,假设您写信并提交了推文。然后随着您的推文,您的应用程序还将发送会话令牌(通过cookie或标题),以便服务器可以识别您是谁。但是令牌只是一个随机的字符串,所以服务器如何知道你是谁从会话令牌?
当服务器收到会话令牌时,它将不会知道用户是谁,因此它将其发送到数据库以从该令牌中检索(4a)实际用户的信息(如UserID)。
如果用户存在并允许执行该操作(即发送推文),则服务器允许它们执行操作。
问题是,第四步是慢性的,需要为用户所做的每一个动作重复。因此,每一个API呼叫都会导致至少两个缓慢的DB呼叫,可以减慢整体响应时间。
使额外的数据库查找更快,以便额外的跳跃无关紧要。
您可以将状态存储在服务器内存中。但是,由于此状态仅在特定服务器上可用,因此这会导致问题。
使用“粘性会话”。在这里,您可以告诉负载均衡器始终在缩放后始终将流量指向特定服务器。这一次会导致不同的缩放问题,如果服务器衰减(缩小),则会丢失所有状态。
JWT,特别是当用作会话时,尝试通过完全消除数据库查找来解决问题。
主要思想是将用户的信息存储在会话令牌中!因此,而不是一些长时间随机字符串,将实际的用户信息存储在会话令牌中。为了保护它,使用唯一只读服务器的秘密签名的令牌的一部分。
因此,即使客户端和服务器可以看到令牌的用户信息部分,第二部分,签名部分只能由服务器验证。
在下面的图片中,令牌的粉红色部分具有有效载荷(用户的信息),可以通过客户端或服务器看到。
但是使用秘密字符串,标题和有效载荷本身签名蓝色部分。因此,如果客户端篡改具有有效载荷(例如冒充不同的用户),则签名将是不同的并且不会被认证。
您使用您的用户名和密码登录:服务器使用用户的信息和秘密创建JWT会话令牌(涉及DB)
然后服务器将JWT令牌发送到前端应用程序。对于未来的活动,用户可以只发送JWT令牌来识别用户而不是每次登录。
接下来,假设您写信并提交了推文。当您发送它,以及您的Tweet的文本时,您的应用程序还将发送JWT令牌(通过cookie或标题),以便服务器可以识别您是谁。但是服务器如何知道你是谁,你是谁来自JWT令牌?嗯,部分令牌已经拥有用户信息。
因此,当服务器收到JWT令牌时,它使用秘密来验证签名部分并从有效载荷部分获取用户信息。从而消除了DB呼叫。
前进为每个用户操作,服务器只需验证签名部分,获取用户信息,并允许用户执行该操作。因此完全跳过DB呼叫。
但是关于JWT令牌,还有一个额外的和重要的事情。也就是说,它使用了到期时间来实现自己。它通常设置为5分钟到30分钟。而且因为它是自包含的,你不能轻易撤消/无效/更新它。这真的是问题的症结所在的地方。
JWT的最大问题是令牌撤消问题。由于它继续工作,直到它到期,因此服务器没有简单的方法来撤销它。
想象一下,您在推特后从Twitter退出。您认为您已被退出使用,但不是这种情况。因为JWT是独立的,并将继续工作,直到它到期。这可能是5分钟或30分钟或任何作为令牌一部分设置的持续时间。因此,如果有人在此期间访问该令牌,他们可以继续访问它,直到它到期。
想象一下,您是Twitter的主持人或某些在线实时游戏,实际用户正在使用该系统。作为主持人,您希望快速阻止某人滥用系统。你不能再出现同样的原因。即使在阻止之后,在令牌到期之前,用户将继续访问服务器。
想象一下,用户是一个管理员,并通过更少的权限将降级为常规用户。再次,这不会立即生效,并且在令牌到期之前,用户将继续成为管理员。
JWT通常不会加密,因此任何能够执行中间攻击和嗅探JWT的人现在都有您的身份验证凭据。这是更容易的,因为只需在服务器和客户端之间的连接上完成MITM攻击。
有人发现,多年来,许多实现JWT的图书馆已经有许多安全问题,甚至规范本身都有安全问题。甚至Auth0本身,促使JWT受到了问题。
在许多复杂的真实应用程序中,您可能需要存储一大吨不同的信息。并将其存储在JWT令牌中可能超过允许的URL长度或饼干长度导致问题。此外,您现在潜在地在每个请求上发送大量数据。
在许多真实世界的应用中,服务器必须维护用户的IP和轨道API以获得速率限制和IP-WhiteListing。因此,您需要使用炽热的快速数据库。要以某种方式思考你的应用程序与JWT无非是现实的。
一个流行的解决方案是在数据库中存储“撤销令牌”列表,并为每个呼叫检查它。如果令牌是撤销列表的一部分,则阻止用户采取下一个操作。但是现在,您正在额外调用DB来检查令牌是否被撤销,因此欺骗了JWT的目的。
虽然JWT确实消除了数据库查找,但它会在这样做时引入安全问题和其他复杂性。安全性是二进制 - 无论是安全的还是不是。因此,为用户会话使用JWT危险。
有方案在后端服务器到服务器 - 服务器(或微服务到微服务)通信,一个服务可以生成JWT令牌,以将其发送到不同的服务以进行授权目的,以及其他窄位置,例如重置密码,您可以在其中发送JWT令牌作为一次性短期令牌以验证用户的电子邮件。
解决方案是根本不使用JWT进行会话目的。而是,做传统,但更有效地进行战斗的方式。
IE。使数据库查找如此炽热(子毫秒),即额外的电话无关紧要。
选项2:让速度快速升起,这无关紧要(一个经过战斗测试的解决方案)
有没有任何数据库,如此快速燃烧它可以在亚毫秒的船舶上提供数百万个请求?
当然,有。它被称为redis!成千上万的公司为每日使用数十亿用户使用Redis只是为了这一确切的目的!
和Redis Enterprise是Redis OSS的增强版本,提供99.999%的可用性,并可以为万亿个请求提供服务。它可以用作私有云上的自由软件,也可以在前3个云中的任何一个云中使用。
更重要的是? Redis Enterprise现在已从仅仅是一个缓存或会话商店演变为完全成熟的多模型数据库,其模块生态系统与核心REDIS一起运行。例如,您可以使用RediSJSON(10x更快的VS.市场领导者),并且基本上有一个实时MongoDB样数据库,或者使用REDISEX模块(4-100x更快),并实行实时全文搜索,如Algolia 。
如果您只需使用REDIS作为会话存储以及一些其他数据库作为主数据库,这就是您的体系结构的样子。有一点要注意的是,Redis Enterprise提供了四种类型的缓存:缓存(懒惰加载),写后面(回写),写字和读副本,与redis OSS仅提供一个(缓存-在旁边)。
请注意,闪电Emoji表示炽热速度。 并且蜗牛emoji表示速度慢。 如前所述,您还可以使用REDIS作为整个数据层的主数据库。 在这种情况下,您的架构变得更加简单,基本上,一切都变得愉快。 当然,公司不仅用作独立数据库,而且是作为一个地理上分布式数据库的集群。