现在很多人使用 JWT 用作 session 管理,这是个糟糕的做法,下面阐述原因,有不同意见的同学欢迎讨论。

首先说明一下,JWT 有两种:

  • 无状态的 JWT,token 中包含 session 数据。

  • 有状态的 JWT,token 中仅有 session ID,session 数据还是存储在服务端。

本文讨论的是 “无状态的 JWT”,就是把用户的 session 数据放到 token 中。

JWT 不适合做为 session 机制,这么做是有危险的。

很多人喜欢比较 “cookies vs. JWT”,这种比较是无意义的,就像比较苹果和桔子,cookies 是一个存储机制,而 JWT 是加密签名的 token,他们不是对立的,可以一起使用,或者独立使用。

正确的比较是“sessions vs. JWT” 和 “cookies vs. Local Storage”。

JWT 宣称的优点

人们通常会说 JWT 有如下的好处:

  • 易于水平扩展
  • 简单易用
  • 加密,更安全
  • 内置过期功能
  • 可以防护 CSRF 攻击
  • 在用户阻止了cookies后还可以工作

对于这些所谓的好处我们会一一剖析。

(1)易于水平扩展

把 session 数据放入 JWT,服务端不需要保存 session 信息,那么服务端自然是无状态的,可以随意扩展。

看上去的确带来了扩展上的便利,但实际上没啥优势,服务器端保存 session 没有任何难度:

  • 多服务器场景:可以用专门的 redis 服务器保存 session。
  • 多集群场景:多集群间不需要共享 session,同一个用户始终分配到同一个集群即可。

这都是很成熟的解决方案,没有必要在客户端 token 中保存 session。

(2)简单易用

看似一个小小的 token 比较简单,实则不然,你需要自己去处理 session 的管理,怎么可能比开箱即用的 cookies 更简单。

(3)更安全

因为 JWT 是加密的,很多人认为其更加安全,cookies 没加密,不安全。

其实 cookies 只是存储机制,你完全可以使用加密签名的方式。

还有人认为 cookies 没加密会被拦截读取。

cookies 只是 HTTP 头信息,不负责安全,这个问题应该使用 TLS 来解决,否则,即使 JWT 也没法保证信息的安全。

(4)内置过期功能

这个功能更是没用,是否过期应该由服务端控制,不应交给客户端控制,否则,如果 token 被盗取,服务端将没有任何办法。

(5)可以防护 CSRF 攻击

简单说一下什么是 CSRF 攻击。

打个比方,你登录了网银,这时已经具备给其他账户转账的条件了,比如转账的接口地址是:

http://xbank.com/transfer?to=123&money=1000

在你没有退出网银之前,你访问了一个恶意网站,其中有一段代码:

<img src=http://xbank.com/transfer?to=456789&money=1000>

这样你就丢钱了。

这只是个朴实的例子,实际情况比这复杂得多,但归根结底,CSRF 攻击就是源于:隐式身份验证机制,就是 cookies 是自动发送给服务端的,无法保证该请求是用户批准的。

所以,很多人就认为使用 JWT 就没这个问题了,因为不用 cookies 了。

那么请问,你是把 JWT 保存在哪里的?有2个保存方式:

  • cookie:这样同样会面临 CSRF 攻击。
  • 其他地方,例如 Local Storage:这样的确避免了 CSRF,但暴露了更严重的安全问题,Local Storage 这类的本地存储是可以被 JS 直接读取的。

其实,防护 CSRF 攻击的正确方式只有:CSRF token。

(6)在用户阻止了cookies后还可以工作

不幸的是,在用户阻止了 cookies 的场景中,通常不仅仅是阻止 cookies,而是阻止所有的本地存储,包括 Local Storage。

这样的话,JWT 也同样无法工作。

JWT 的缺点

(1)体积大

如果把 session 信息编码后放入 token,那么其体积会很大,很有可能超出 cookie 的大小限制,那就只能把 JWT 保存在 Local Storage 了,也就产生了安全问题。

而且,体积大,网络压力就大了。

(2)不安全

这个问题上面分析过了,如果放在 cookie 里,那和传统的 session 方案就差不多了,如果放在别的地方,就有其他安全问题了。

(3)无法使某个 JWT 无效

不像 session,在服务端可以使其失效,而 JWT 直到其过期才能无效。

比如服务端检测到了一个安全威胁,也无法使相关的 JWT 失效。

也就是说,当你发现风险时,无法杀死某个 session,如果你想解决这个问题,就需要服务端可以对 session 进行管理,那么就变回有状态的模式了。

(4)session 数据旧了

session 数据是保存在 JWT 中的,其中会有用户的相关信息,例如角色。

在 JWT 过期之前,用户的角色发生了变化,那么这时 JWT 中的信息就是旧的了,因为无法更新。

小结

JWT 真的不适合当做 session 使用,JWT 更适合一次性的命令认证,设置一个很短的有效期。

本文的目的不是说 JWT 不好,而是想说把 JWT 用作 session 是用错了地方。

你是怎么使用 JWT 的?欢迎交流讨论。

翻译整理自:

http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/

推荐阅读:

不要把 JWT 用作 session的更多相关文章

  1. jwt、session、oauth 异同

    1,jwt 和session机制 首先jwt 和session机制 都是用户认证的,oauth 不是 session 的流程: 1.用户向服务器发送用户名和密码. 2.服务器验证通过后,在当前对话(s ...

  2. ASP.NET Core Web Api之JWT VS Session VS Cookie(二)

    前言 本文我们来探讨下JWT VS Session的问题,这个问题本没有过多的去思考,看到评论讨论太激烈,就花了一点时间去研究和总结,顺便说一句,这就是写博客的好处,一篇博客写出有的可能是经验积累,有 ...

  3. JWT与Session的比较

    如今,越来越多的项目开始采用JWT作为认证授权机制,那么它和之前的Session究竟有什么区别呢?今天就让我们来了解一下. JWT是什么 定义 JSON Web Token(JWT)是一个开放标准(R ...

  4. JWT与Session比较和作用

    1. JSON Web Token是什么 JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的.自包含的方式,用于作为JSON对象在各方之间安全地传输信息.该 ...

  5. 用户认证:基于jwt和session的区别和优缺点

    背景知识: Authentication和Authorization的区别: Authentication:用户认证,指的是验证用户的身份,例如你希望以小A的身份登录,那么应用程序需要通过用户名和密码 ...

  6. jwt vs session 以rails 为例 (翻译部分)

    原文地址:https://pragmaticstudio.com/tutorials/rails-session-cookies-for-api-authentication 普通方式: 令牌为基础的 ...

  7. 认证 协议 JWT OAuth Session Cookie

    本文翻译自Auth-Boss. 如果有翻译的不恰当或不对的地方, 欢迎指出. 成为一个认证老司机, 了解网络上不同的身份认证方法. 本文档的目的是记录和编目Web上的身份验证方法.认证指的是创建一个系 ...

  8. 一文说通Jwt、Session、Cooike区别

    JWT 全称是 JSON Web Token,是目前非常流行的跨域认证解决方案,在单点登录场景中经常使用到. 有些人觉得它非常好用,用了它之后就不用在服务端借助 redis 实现认证过程了,但是,还有 ...

  9. 你在用 JWT 代替 Session?

    现在,JSON Web Tokens (JWT) 是非常流行的.尤其是 Web 开发领域. 流行 安全 稳定 易用 支持 JSON 所有这些因素,令 JWT 名声大振. 但是,今天我要来说说使用 JW ...

随机推荐

  1. 原生js实现响应式轮播图,支持电脑端点击切图,手机端滑动切图

    轮播图的实现原理并不难,但是步骤有些繁琐.最近练习了一个轮播图,大部分是跟着网上的教程写的,然后自己做了一点兼容ie8的修改,加了点击切换图片的特效和手机端的滑动特效,让这个轮播图可以在响应式的网站中 ...

  2. P1035 台阶问题二

    题目描述 有 \(N\) 级的台阶,你一开始在底部,每次可以向上迈最多 \(K\) 级台阶(最少 \(1\) 级),问到达第 \(N\) 级台阶有多少种不同方式. 输入格式 两个正整数 \(N, K( ...

  3. int64 DWORD 与cstring 互转

    //int64 与cstring 互转 int64_t val = 1111111111111111111; CString str; str.Format(("%I64d"), ...

  4. Git的使用--如何将本地项目上传到Github(两种简单、方便的方法..)

    https://blog.csdn.net/u014135752/article/details/79951802 总结:其实只需要进行下面几步就能把本地项目上传到Github 1.在本地创建一个版本 ...

  5. Linux 设备模型

    在 2.5 开发循环中一个声明的目标是为内核创建一个统一的设备模型. 之前的内核没有单一的数据结 构, 使它们可以来获取关于系统如何整合的信息. 尽管缺乏信息, 有时事情也进行的不错. 新系统, 带 ...

  6. Qt4.5 QFrame(相当于Delphi里的TPanel,有各种凹凸方式)

    QFrame类是有框架的窗口部件的基类. QPopupMenu使用这个来把菜单“升高”,高于周围屏幕.QProgressBar有“凹陷”的外观.QLabel有平坦的外观.这些有框架的窗口部件可以被改变 ...

  7. 编写自己的JDBC框架(转)

    一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...

  8. Python3 安装pylint 及与PyCharm关联

    使用如下命令: pip3 install pylint 安装完后可以看到在你的python3的目录底下的Scripts目录下有pylint.exe了 然后就可以使用pylint 评估你的代码了,如: ...

  9. 雪花算法 Snowflake & Sonyflake

    唯一ID算法Snowflake相信大家都不墨生,他是Twitter公司提出来的算法.非常广泛的应用在各种业务系统里.也因为Snowflake的灵活性和缺点,对他的改造层出不穷,比百度的UidGener ...

  10. 牛客国庆days赛 地铁

    传送门:https://ac.nowcoder.com/acm/problem/52805 我佛了,还能跑边图啊!!! 跑边图不能用vector啦啦啦啦啦 具体也不难,就直接上代码了 #include ...