【发布时间】:2020-08-29 13:57:37
【问题描述】:
在身份验证等情况下,与会话相比,使用 JWT 有什么优势?
它是用作独立方法还是在会话中使用?
【问题讨论】:
在身份验证等情况下,与会话相比,使用 JWT 有什么优势?
它是用作独立方法还是在会话中使用?
【问题讨论】:
与使用“会话”本身相比,JWT 没有任何好处。 JWT 提供了一种在客户端而不是在服务器上维护会话状态的方法。
人们问这个问题时通常的意思是“使用 JWT 与使用 服务器端会话相比有什么好处”。
对于服务器端会话,您要么必须将会话标识符存储在数据库中,要么将其保存在内存中并确保客户端始终访问同一个服务器。这两个都有缺点。在数据库(或其他集中式存储)的情况下,这将成为一个瓶颈和需要维护的东西 - 本质上是对每个请求进行的额外查询。
使用内存解决方案,您会限制水平扩展,并且会话会受到网络问题(客户端在 Wifi 和移动数据之间漫游、服务器重启等)的影响。
将会话移至客户端意味着您移除了对服务器端会话的依赖,但它也带来了一系列挑战。
这些问题由 JWT 和其他类似的客户端会话机制共享。
JWT 尤其解决了其中的最后一个问题。了解什么是 JWT 可能会有所帮助:
这是一些信息。对于用户会话,您可以包括用户名和令牌过期的时间。但它可以是任何东西,甚至是会话 ID 或用户的整个配置文件(但请不要这样做)。
它有一个安全的签名,可以防止恶意方生成假令牌(您需要访问服务器的私钥才能对其进行签名,并且您可以验证它们在签名后没有被修改)。
您将它们与每个请求一起发送,就像发送 cookie 或 Authorization Header 一样。事实上,它们通常在 HTTP Authorization 标头中发送,但使用 cookie 也可以。
令牌已签名,因此服务器可以验证其来源。我们将假设服务器信任自己的安全签名能力(您应该使用标准库:不要尝试自己做,并正确保护服务器)。
关于安全传输令牌的问题,答案通常是通过加密通道发送,通常是 httpS。
关于将令牌安全地存储在客户端中,您需要确保坏人无法获取它。这(主要)意味着防止来自不良网站的 JS 读取令牌以将其发回给他们。使用用于缓解其他类型 XSS 攻击的相同策略可以缓解这种情况。
如果您需要使 JWT 失效,肯定有办法实现这一点。仅为请求终止“其他会话”的用户存储每个用户的 epoch 是一种非常有效的方法,可能已经足够好了。如果应用程序需要每个会话失效,那么可以以相同的方式维护会话 ID,并且“已删除令牌”表仍然可以维护为比完整的用户表小得多(您只需要保留比最长允许的令牌生命周期)。因此,使令牌无效的能力部分否定了客户端会话的好处,因为您必须保持此会话终止状态。这很可能是一个比原始会话状态表小得多的表,因此查找仍然更有效。
使用 JWT 令牌的另一个好处是,使用您可能期望拥有的所有语言中可用的库来实现相当容易。它也完全脱离了您最初的用户身份验证方案 - 如果您迁移到基于指纹的系统,则无需对会话管理方案进行任何更改。
一个更微妙的好处:因为 JWT 可以携带“信息”并且可以被客户端访问,您现在可以开始做一些聪明的事情。例如,提醒用户他们的会话将在他们注销前几天到期,让他们可以根据令牌中的到期日期重新进行身份验证。随心所欲。
简而言之:JWT 回答了其他会话技术的一些问题和缺点。
“更便宜”的身份验证,因为您可以消除数据库往返(或者至少有一个小得多的表要查询!),这反过来又实现了水平可扩展性。
防篡改客户端声明。
虽然 JWT 没有解决安全存储或传输等其他问题,但它不会引入任何新的安全问题。
JWT 存在很多负面因素,但如果您实现与其他类型身份验证相同的安全性,那就没问题了。
最后一点:它也不是 Cookie 与令牌。 Cookies 是一种用于存储和传输信息位的机制,也可用于存储和传输 JWT 令牌。
【讨论】:
简短的回答是:无。
更长的版本是:
在阅读the GraphQL docs 中的此建议后,我实施了 JWT 进行会话管理:
如果您不熟悉任何这些身份验证机制,我们 推荐使用 express-jwt 因为它很简单而不牺牲 任何未来的灵活性。
实现确实很简单,因为它只是增加了一点复杂性。然而,过了一会儿,我(和你一样)开始想知道有什么好处。事实证明,就会话管理而言,JWT 很少(或可能没有),正如这篇博文详细解释的那样:
【讨论】:
abc.example.com 和 example.com 通常被浏览器视为同一个站点。
我有一个类似的问题,在 JWT 和令牌 + 缓存之间进行用户身份验证。
阅读这些文章后,我很清楚 JWT 承诺的好处并没有超过它带来的问题。所以令牌+缓存(Redis/Memcached)是我要走的路。
Auth Headers vs JWT vs Sessions — How to Choose the Right Auth Technique for APIs
【讨论】:
我的两分钱,在路上与 joepie91 的著名博文形成对比。
考虑到今天(和明天)的应用程序(大部分)是云原生的
无状态 JWT 身份验证具有经济效益,
随着应用程序的扩展而扩展:
云应用程序每过一秒都会产生成本。
当用户不再需要“针对”会话存储进行身份验证时,此成本就会降低。
处理
24/7 全天候运行会话商店需要花钱。
在 K8S 的世界中,您无法摆脱基于内存的解决方案,因为 pod 是短暂的。
出于完全相同的原因,粘性会话不会很好。
存储
存储数据需要花钱。在 SSD 中存储数据的成本更高。
会话相关操作需要快速解决,所以不能选择光驱。
I/O
一些云提供商会为与光盘相关的 I/O 收费。
带宽
一些云提供商对服务器实例之间的网络活动收费。
这适用,因为几乎可以肯定 API 和会话存储是单独的实例。
会话存储集群
成本进一步增加了所有上述成本。
【讨论】:
如果您在 AWS 上,另一个稍微不同的观点可能会很有用。
我们在 AWS ElastiCache 上实施了 PHP5.x 会话存储,以跨多个服务器集中会话存储。
在我们迁移到 PHP7 之前,它一直运行良好。很难为 PHP7 进行配置,并且我们一直受到间歇性问题的困扰,对于特定用户,会话似乎“失败/不匹配/有点混乱”,然后他们无法登录该设备,直到旧会话过期。
我们转而使用 DynamoDb 来存储会话,不再出现问题。它稍微慢一些,但仅在登录(会话存储)阶段才明显。
在此过程中,我们实施了 AWS cognito 来替换我们的身份验证,并开始使用 API-Gateway 通过 lambda python 函数传递内容。
我们使用 PHP SDK 向 Cognito 进行身份验证,然后将 JWT 存储在 cookie 中,但仍然使用 PHP 会话来保持我们的旧代码正常工作。
现在我们有两个堆栈,两全其美:PHP7 做到了一点,将主要内容提供给用户(非常快速)。然后 JS 接管并使用 JWT 提供额外的内容。
我认为 JWT 的优点在于它可以在这两个堆栈之间传递并用于在两种情况下对用户进行身份验证。
现在我们想知道是否值得冒险并完全切换到新的 JWT 系统?
在 PHP 中,我们仍然使用旧会话,但我们还将令牌传递给 cognito 以对其进行身份验证。这是一点额外的安全性,可能不是必需的,但它给人一种温暖舒适的感觉。再说一次,使用 dynamoDb 可以节省成本和维护。
【讨论】: