设为首页 加入收藏

TOP

别再用 JWT 作为 Session 系统了,问题重重,后果很危险!(一)
2023-07-25 21:38:41 】 浏览:57
Tags:别再用 JWT 作为 Session 后果很 危险

JSON Web Tokens,又称 JWT。本文将详解:为何 JWT 不适合存储 Session,以及 JWT 引发的安全隐患。望各位对JWT有更深的理解!

十分不幸,我发现越来越多的人开始推荐使用 JWT 管理网站的用户会话(Session)。在本文中,我将说明为何这是个非常非常不成熟的想法。

为了避免疑惑和歧义,首先定义一些术语:

  • 无状态 JWT(Stateless JWT):包含 Session 数据的 JWT Token。Session 数据将被直接编码进 Token 内。
  • 有状态 JWT(Stateful JWT):包含 Session 引用或其 ID 的 JWT Token。Session 数据存储在服务端。
  • Session token(又称 Session cookie):标准的、可被签名的 Session ID,例如各类 Web 框架(译者注:包括 Laravel)内已经使用了很久的 Session 机制。Session 数据同样存储在服务端。

需要澄清的是:本文并非挑起「永远不要使用 JWT」的争论 —— 只是想说明 JWT 并不适合作为 Session 机制,且十分危险。JWT 在其它方面的确有其用武之地。本文结尾,我将简短地介绍一些合理用途。

首先需要说明

很多人错误地尝试比较 CookiesJWT。这种对比毫无意义,就像对比内存和硬盘一样。Cookies 是一种存储机制,然而 JWT Tokens 是被加密并签名后的令牌。

它们并不对立 —— 相反,他们可以独立或结合使用。正确的对比应当是:Session 对比 JWT,以及 Cookies 对比 Local Storage

在本文中,我将把 JWT Tokens 同 Session 展开对比,并偶尔对比 CookieLocal Storage。这样的比较才有意义。

推荐一个开源免费的 Spring Boot 最全教程:

https://github.com/javastacks/spring-boot-best-practice

JWT 坊间流传的优势

在人们安利 JWT 时,常常宣扬以下几点好处:

  • 易于水平扩展
  • 易于使用
  • 更加灵活
  • 更加安全
  • 内置过期时间功能
  • 无需询问用户「本网站使用 Cookies」
  • 防止 CSRF 攻击
  • 更适用于移动端
  • 适用于阻止 Cookies 的用户

我将会逐条阐述以上观点为何是错误或误导性的,其中部分解释可能会有些模糊,这主要是因为这些「好处」的表述本身就比较模糊。

易于水平扩展?

这是列表中唯一一条在技术层面部分正确的「好处」,但前提是你使用的是无状态 JWT Tokens。然而事实上,几乎没人需要这种横向扩展能力。有很多更简单的拓展方式,除非你在运维像淘宝这样体量的系统,否则根本不需要无状态的会话(Stateless sessions)。

一些扩展有状态会话(Stateful sessions)的例子:

  1. 「在单台服务器上运行多个后端进程」 :只需在此服务器上安装 Redis 服务用于存储 Session 即可。
  2. 「运行多台服务器」 :只需一台专用的 Redis 服务器用于存储 Session 即可。
  3. 「在多集群内运行多台服务器」 :会话保持(又称:粘滞会话)。

以上所有场景在现有软件系统内都具备良好的支持,你的应用需要进行特殊处理的可能性基本为零。

或许你在想,应当为你的应用预留更多调整空间,以防未来需要某些特殊操作。但实践告诉我们,以后再替换 Session 机制并不困难,唯一的代价是,在迁移后所有用户将被强制登出一次。我们没必要在前期实现 JWT,尤其是考虑到它所带来的负面影响。

易于使用?

这个真没有。你不得不自行处理 Session 的管理机制,无论是客户端还是服务端。然而标准的 Session cookies 则开箱即用,JWT 并没有更简单。

说白了,目前各种开箱即用的框架并没有自动集成 JWT,需要研发人员自行处理。

更加灵活?

我暂时还没看到有人成功地阐述「JWT 如何更加灵活」。几乎每个主流的 Session 实现,都允许你直接把数据存储进 Session,这跟 JWT 的机制并没有差别。据我所知,这只是个流行语罢了。

更加安全?

一大批人认为 JWT Tokens「更加安全」,理由是使用了加密技术。实际上,签名后的 Cookies 比未签名的 Cookies 同样更加安全,但这绝不是 JWT 独有的,优秀的 Session 实现均使用签名后的 Cookies(译者注:例如 Laravel)。

「使用加密技术」并不能神奇地使某些东西更加安全,它必须服务于特定目的,并且是针对该目的的有效解决方案。错误地使用加密反而可能会降低安全性。

另一个我听过很多次的对于「更加安全」的论述是「JWT 不使用 Cookies 传输 Tokens」。这实在是太荒谬了,Cookie 只不过是一条 HTTP 头信息,使用 Cookies 并不会造成任何不安全。事实上,Cookies 受到特别良好的保护,用于防止恶意的客户端代码。

如果担心有人拦截掉你的 Session cookies,那你应当考虑使用 TLS。如果不使用 TLS,任何类型的 Session 机制都可能被拦截,包括 JWT。

内置过期时间功能?

无意义,又没什么卵用的特性。在服务端也能实现过期控制,有不少 Session 实现就是这么做的。实际上,服务端的过期控制更加合理,这样你的应用就可以清除不再需要的 Session 数据;若使用无状态 JWT Tokens 且依赖于它的过期机制,则无法执行此操作。

这个过期时间在某些场景实际上是增加了复杂度的。

无需询问用户「本网站使用 Cookies」?

完全错误。并没有什么「Cookies 法律」—— 有关 Cookies 的各种法律实际上涵盖了任何类型「对某项服务的正常运行非严格必须的持久性 ID」,任何你能想到的 Session 机制都包括在内。

译者注:然鹅中国并没有。

简单来说:

  • 若出于系统功能目的使用 Session 或 Token(例如:保持用户的登录态),那么无论怎样存储 Session 均无需征得用户同意。
  • 若出于其他目的使用 Session 或 Token(例如:数据分析、追踪),那么无论怎样存储 Session 都需要询问用户是否允许。

防止 CSRF 攻击?

这个真真的没有。存储 JWT Tokens 的方式大概有两种:

  • 「存入 Cookie」 :仍然易受 CSRF 攻击,还是需要进行特殊处理,保护其不受攻击。
  • 「其他地方,例如 Local Storage」 :虽然不易受到 CSRF 攻击,但你的网站需要 java script 才能正常访问;并且又引发了另一个完全不同,或许更加严重的漏洞。我将在后文详细说明。

预防 CSRF 攻击唯一的正确方法,就是使用 CSRF Tokens。Session 机制与此无关。

更适用于移动端?

毫无根据。目前所有可用的浏览器几乎都支持 Cookies,因此也支持 Session。同样,主流的移动端开发框架以及严谨的 HTTP 客户端库都是如此。这根本不是个问题。

适用于阻止 Cookies 的用户?

不太可能。用户通常会阻止任何意义上的持久化数据,而不是只禁止 Cookies。例如,Local Storage 以及任何能够持久化 Session 的存储机制(无论是否使用 JWT)。不管你出于多么简单的目的使用 JWT 都无济于事,这是另一个完全独立的问题了。另外,试图让身份认证过程在没有 Cookies 的情况下正常进行,基本没戏。

最重要的是,禁用掉所有 Cookies 的多数用

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇微软的148座坟墓 下一篇2.Spring-HelloSpring

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目