身份验证:JWT使用率与会话


122

在身份验证之类的情况下,通过JWT进行会话有什么好处?

它是作为独立方法使用还是在会话中使用?

Answers:


211

JWT不能说每个会话都使用“会话”。JWT提供了一种在客户端上维护会话状态的方法,而不是在服务器上进行维护。

人们常问的意思是“使用JWT相对于使用服务器端会话有什么好处?

对于服务器端会话,您要么必须将会话标识符存储在数据库中,要么将其保留在内存中,并确保客户端始终访问同一服务器。这两个都有缺点。对于数据库(或其他集中式存储),这将成为瓶颈和需要维护的工作-本质上是对每个请求都要执行的额外查询。

使用内存中解决方案,您可以限制水平扩展,并且会话将受到网络问题的影响(客户端在Wifi和移动数据之间漫游,服务器重新启动等)

将会话移至客户端意味着您删除了对服务器端会话的依赖性,但是这带来了一系列挑战。

  • 安全地存储令牌
  • 安全运输
  • JWT的会话有时很难失效。
  • 信任客户的要求。

JWT和其他客户端会话机制都共享这些问题。

JWT特别解决了其中的最后一个问题。了解什么是JWT可能会有所帮助:

这是一些信息。对于用户会话,您可以包括用户名和令牌过期的时间。但是可以想象,它可以是任何东西,甚至包括会话ID或用户的整个个人资料。(但是请不要这样做)它具有一个安全的签名,可以防止恶意方生成伪造的令牌(您需要访问服务器的私钥来对其进行签名,并且可以验证它们在签名后没有被修改)。发送每个请求,就像Authorization发送Cookie或Header 一样。实际上,它们通常在HTTP Authorization标头中发送,但是使用cookie也可以。

令牌已签名,因此服务器可以验证其来源。我们将假定服务器信任自己的安全签名能力(您应该使用标准库:请勿尝试自己做,并正确保护服务器)

关于安全传输令牌的问题,答案通常是通过加密通道(通常是httpS)发送令牌。

关于将令牌安全地存储在客户端中,您需要确保坏人无法使用它。这(主要是)意味着防止不良网站的JS读取令牌并将其发回给它们。使用与缓解其他类型的XSS攻击相同的策略可以缓解这种情况。

如果您需要使JWT失效,那么肯定有一些方法可以实现。仅为请求“其他会话终止”的用户存储每个用户的纪元是一种非常有效的方法,可能已经足够了。如果应用程序需要按会话无效​​,则可以以相同的方式维护会话ID,并且仍可以将“ killed tokens”表维护为小于完整用户表(您只需保留比因此,使令牌无效的能力会部分抵消客户端会话的好处,因为您必须保持此会话的终止状态。该表很有可能比原始会话状态表小得多,因此查找仍然更加高效。

使用JWT令牌的另一个好处是,使用可能支持您期望使用的每种语言的库可以很容易地实现。它也与您的初始用户身份验证方案完全脱离-如果您使用基于指纹的系统,则无需对会话管理方案进行任何更改。

一个更微妙的好处:因为JWT可以携带“信息”,并且客户端可以访问它,所以您现在可以开始做一些聪明的事情。例如,提醒用户他们的会话将在注销前几天到期,并根据令牌中的到期日期为他们提供重新认证的选项。随你所想。

简而言之:JWT回答了其他会话技术的一些问题和缺点。

  1. “更便宜”的身份验证,因为您可以消除数据库往返(或至少要查询的表要少得多),从而实现水平可伸缩性。
  2. 防篡改的客户端声明。

尽管JWT不能解决安全存储或传输之类的其他问题,但它并未引入任何新的安全性问题。

JWT周围存在很多消极因素,但是如果您实现与其他类型的身份验证相同的安全性,那将很好。

最后一点:不是Cookie还是代币。Cookies是一种用于存储和传输信息位的机制,也可以用于存储和传输JWT令牌。


4
值得注意的是,服务器端会话也不必在服务器上存储任何信息。服务器可以像JWT一样将客户端用作存储。真正的区别在于1)通过将值作为Cookie头以外的请求头传递来避免浏览器安全规则,以及2)JWT具有标准化格式。
Xeoncross

1
您说在本地存储中存储jwt是安全的吗?如果没有,在哪里可以安全保存它,以便用户保持登录状态?
杰西卡

1
是的,本地存储通常是在客户端存储它的最正确的地方。您确实需要处理XSS-我不是Web编程专家,但请查看此答案stackoverflow.com/a/40376819/1810447并搜索“如何
防范

1
在您的评论中,您不会谈论基于缓存的解决方案+会话令牌。在我看来,这比JWT +“ killed令牌”表“更好”,因为使用此“ killed Tokens”表,无论如何您都需要数据库访问,并且还需要会话+缓存(也很小)。与持久会话相比,持久JWT的实现更加痛苦,因为您需要使用refresh_token(因此需要维护两个令牌)……任何评论将不胜感激……尤其是如果您有一些数字来展示JWT + kill_table比会话+缓存更有效;-)
tobiasBora

2
不建议使用@TheTahaan localStorage存储JWT。您共享的链接也提到了这一点。该博客很好地解释了为什么不应该将JWT存储在localStorage中。
Harke)

40

简短的答案是: 无。

较长的版本是:

阅读GraphQL docs中的建议后,我实现了用于会话管理的JWT

如果您不熟悉这些身份验证机制中的任何一种,我们建议使用express-jwt,因为它很简单,而且不会牺牲任何将来的灵活性。

实现确实很简单,因为它只增加了一点点复杂性。过了一会儿,我(像您一样)开始想知道这些好处是什么。事实证明,就会话管理而言,JWT很少(或可能没有),正如此博客文章详细解释的那样:

停止使用JWT进行会话


0

我的两美分,这与joepie91著名的博客文章形成了鲜明的对比。

考虑到当今(以及未来)的应用程序(大部分)都是云原生
的。无状态JWT身份验证具有经济利益,它随着应用程序的扩展而扩展:
云应用程序伴随着人们的一口气而招致成本
当用户不再需要“针对”会话存储进行身份验证时,可以降低此成本。

处理
24/7全天候运行会话存储需要花费金钱。
在K8S的世界中,您无法摆脱基于内存的解决方案,因为吊舱是短暂的。
完全相同的原因,粘性会话的效果不佳。

存储
存储数据需要花费金钱。将数据存储在SSD中的成本甚至更高。
与会话相关的操作需要快速解决,因此无法选择光盘驱动器。

I / O
一些云提供商会为与光盘相关的I / O收费。

带宽
一些云提供商对服务器实例之间的网络活动收费。
这适用,因为几乎可以确定API和会话存储是单独的实例。

将会话存储集群化
该成本将所有上述成本进一步提升。


“由于Pod是短暂的,因此您无法摆脱K8S世界中基于内存的解决方案。”不确定您的意思是什么。Redis肯定可以在K8S环境中工作,而且Redis Pod频繁失败足以影响您的用户的可能性很小。
quietContest

@quietContest在构建软件时,我个人不希望处理可能性。顺便说一句,除了解决方案的稳定性外,攻击还可能导致软件故障和Pod重新启动,这将导致会话丢失。因此,我选择基于JWT的解决方案。
Eyal Perry

1
“我个人更喜欢在构建软件时不考虑可能性”。我认为我们所有人都希望这样做,这就是为什么我们不应该构建依赖于内存中数据存储的系统而不会失败的原因,因为这样做的可能性似乎相当高。至于您的另一点,如果您的攻击者能够始终关闭您的redis实例,那么解决该问题的方法可能不需要使用JWT。
quietContest

在这方面,@ quietContest持续进行或一生中一次活动对我而言都是相同的。也就是说,放置良好的DDoS攻击可能导致服务器“注销用户”。对于软件的可靠性声誉而言,这做得不好。无论如何,我认为redis对于会话管理来说是多余的。它的成本很高,需要扩展,而(安全地)不将JWT存储在cookie中。
Eyal Perry

1
@quietContest感谢您的输入,喜欢讨论!
Eyal Perry

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.