A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

现在,JSON Web Tokens (JWT) 是非常流行的。尤其是 Web 开发领域。
  • 流行
  • 安全
  • 稳定
  • 易用
  • 支持 JSON
所有这些因素,令 JWT 名声大振。
但是,今天我要来说说使用 JWT 的缺点。也就是为什么说将 JWT 用于会话控制是多么的糟糕。
为什么使用 JWT?如果你不了解 JWT,不要紧张,它并不可怕。
JWT 只是用于网络间传递声明而执行一种基于 JSON 的标准。
例如,我是个盲人,而且听力也不好。你上周帮我买了午餐,现在我需要你的收款账号,把钱还给你。如果我询问你的账号,但是其他人高呼他们的账号,由于我把别人的账号误认为是你的,我可能会不小心把钱打给别人。
JWT 旨在防止这种情况发生。JWT 提供了一种简单的方法,在彼此传递数据时,验证是由谁先创建了数据。
所以,像上述的例子,即使我收到了超过 100 万个 JWT 返回的账号信息,我也很容易可以辨别出来哪个真实来自于你。
JWT 如何运行?JWT 是 JSON 格式的被加密了的字符串。


JWT 的核心是密钥,就是 JSON 数据。这是你关心的,并希望安全传递出去的数据。JWT 如何做到这一点,并使你信任它,就是加密签名。
比如说,我写了一封信,当我署名这封信时,意味着只要读过这封信的人,都知道是我写了这封信。而且我的签名是独一无二的,所以不会被怀疑真实性。加密签名的方式大致相同,JWT 有两种加密方式:对称加密和非对称加密,两种方式有同等的效用。
JWT 内容加密其实,JWT 的内容(内部的 JSON 数据)通常是不加密的。这意味着,即使没有密钥,也可以查看 JWT 内的数据。JWT 默认并不会加密你的数据,它只是帮助你验证是你信任的一方创建了它。
如果你确实需要加密 JWT 内容,可以使用 JWE 进行加密,但这种做法并不常见。请确保使用了正确的方法。
如今人们是如何使用 JWT 的?JWT 最常见的用途是身份验证。有大量的 Web 安全库使用 JWT 创建会话控制,API 令牌等。
这种做法通常是,当需要对网站/ API 进行身份验证时,服务器生成一个包含用户 ID 的 JWT,以及其它一些关键性的信息,然后再将其发送给浏览器/客户端等,存储为会话令牌。


例如,当用户访问网站上的另一个页面时,浏览器会自动将该 JWT 发送到服务器,服务器验证 JWT 确认和最初创建的令牌相同,然后允许用户执行后续的操作。
从理论上看,还不错,因为:
  • 当服务器收到 JWT 时,可以验证其是否是合法的,是否是信任用户的令牌
  • 可以在服务器本地验证,而不需要任何其它的网络请求,与数据库的通信等。这可能令管理会话更高效,因为无需从数据库(缓存)加载用户信息,只需要在本地运行一小部分代码。这可能是人们喜欢用 JWT 的最大原因。
似乎很棒,既可以提高 Web 应用的性能,又可以减少缓存服务器和数据库服务器的负载,提供更好的体验。另外你还可以在 JWT 中存储用户权限信息、用户个人信息等等更多的额外信息进一步减少数据库压力。
为什么 JWT 不是最好的会话令牌?我们已经了解了 JWT 如何用于身份验证,让我们进入本篇的中心话题:为什么 JWT 不是最好的会话令牌,为什么普通的旧会话方式在几乎各方面都优于 JWT。
背景我们先了解一些背景知识。开发人员构建的大多数网站都相对比较简单:
  • 用户注册
  • 用户登录
  • 用户点击执行操作
  • 网站使用用户信息进行创建、删除、更新、查阅信息
对于这类网站,要知道用户进行交互的每个页面都会包含某些动态数据。比如:你正在访问一个需要用户登录才能进一步操作的网站,你经常会在数据库中对用户进行这些操作:
  • 记录用户正在执行的操作
  • 将用户的某些信息添加到数据库中
  • 检查用户的权限看其是否可以执行某项操作
  • 等等
数据我们来看两种方案:
  • 在 Cookie 中存储用户 ID(abc123)
  • 在 JWT 中存储用户 ID(abc123)
如果我们将 ID 存储在 Cookie 中,需要 6 个字节。如果将 ID 存储在 JWT 中(设置基本的请求头字段,以及一些其它信息),需要几百字节甚至更多。对于简单的会话控制,每个页面的请求就增大了几十倍。


假如你的网站每月有 10 万次的浏览器,就意味着要多开销几十兆的流量。听起来并不多,但日积月累也是不小一笔开销。实际上,许多人会在 JWT 中存储的信息会更多。
无论如何你需要操作数据库如上所述,大多数需要用户登录的网站主要是 CRUD 操作(增查改删)生成动态内容。


在网站上使用 JWT,对于用户加载的几乎所有页面,都需要从缓存/数据库中加载用户信息,可能出现下列情况:
  • 需要用户关键性信息查询(例如:判断用户账号是否有足够的资金完成交易?)
  • 需要将一些信息保存进数据库(例如:用户相关的唯一信息,需要根据该信息对用户进行检索)
  • 必须从缓存/数据库中查询完整的信息,方便网站生成完整的动态页面内容。
想想你的网站是否会遇到上述情形。这意味着大多数网站不适用 JWT 的无状态特性。为了解决这个问题,就需要 JWT 变得更大,而且需要使用 CPU 来计算签名,就会导致比传统会话慢许多。
其实,几乎每个 Web 框架支持在每次请求传入用户信息,这包括 Django,Rails,Express.js 等(如果有用到身份验证功能)。另外,如果你使用 Memcached/Redis 等缓存服务器对用户信息进行缓存,检索会变得非常快。
多余的签名JWT 的卖点之一就是加密签名,由于这个特性,接收方得以验证 JWT 是否有效且被信任。
但是,其实在过去 20 年中几乎每一个框架对于普通会话 Cookie 都可以获得很好的加密签名处理。这意味着你可以获得与 JWT 完全一致的效果,况且大多数 Web 身份认证应用中,JWT 都会被存储到 Cookie 中,这就是说你有了两个层面的签名。
听着似乎很赞,但是没有任何优势,为此,你需要花费两倍的 CPU 开销来验证签名。对于有着严格性能要求的 Web 应用,这并不理想,尤其对于单线程环境。
更好的解决方案是什么?如果你正在构建上述类型的网站,那么最好选择旧的,简单且安全的服务器端会话。而不是将用户 ID 存储到 JWT 中,然后再将 JWT 存储到 Cooike 中。只需将用户 ID 直接存储到 Cookie 中即可。
如果你的网站很受欢迎,有着大的访问量,可以将会话缓存到 Memcached/Redis,同时也有利于扩展你的服务。
什么时候使用 JWT?JWT 虽然对于大多数网站都没有用,但是有几种情况它是很有用的。
如果你正在构建从服务器到服务器或客户端到服务器(如:移动应用 APP 或单页面应用)的 API 服务,那么使用 JWT 是非常明智的。比如:
  • 你的客户端需要通过 API 进行身份验证,并返回 JWT
  • 然后,客户端使用返回的 JWT 经过身份验证去请求其它的 API 服务
  • 这些其它 API 服务通过客户端的 JWT 验证客户端是可信的,并且可以执行某些操作无需再次验证


对于这类 API 服务,JWT 非常适合,因为客户端需要频繁进行请求,并且权限是可控的,通常认证数据以无状态方式持久存在,不需要过多依赖用户信息。
如果你正在构建的应用类似单点登录或 OpenID Connect 认证,JWT 同样十分适合,就是实现一种通过第三方验证用户的方法。
总结当你准备构建下一个网站时,只需要使用 Web 框架默认的身份认证功能即可,不需要再集成 JWT 方式。



链接:https://juejin.im/post/5b8a99f3e51d4538bf55dbf9



1 个回复

倒序浏览
奈斯
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马