(译)别再使用 JWT 作为 Session 系统!问题重重且很危险。

JSON Web Tokens,又称 JWT。本文作者将详解:为何 JWT 不适合存储 Session,以及 JWT 引发的安全隐患。望各位使用前三思。

原文地址:http://cryto.net/~joepie91/blog/2016/06/13...
断断续续翻译了一周,今天终于审校一下,算是填坑完毕。自己博客广告走一波:https://wi1dcard.cn/

十分不幸,我发现越来越多的人开始推荐使用 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。这样的比较才有意义。

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 如何更加灵活」。几乎每个主流的 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 攻击,但你的网站需要 JavaScript 才能正常访问;并且又引发了另一个完全不同,或许更加严重的漏洞。我将在后文详细说明。

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

更适用于移动端?

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

适用于阻止 Cookies 的用户?

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

最重要的是,禁用掉所有 Cookies 的多数用户都明白这会导致身份认证无法使用,他们会单独解锁那些他们比较关心的站点。这并不是你 —— 一个 Web 开发者应当解决的问题。更好的方案是,向你的用户们详细地解释为何你的网站需要 Cookies 才能使用。

JWT 的劣势

以上,我已经对常见的误解做了说明,以及为什么它们是错误的。你或许在想:「这好像也没什么大不了的,即便 JWT 无法带来任何好处,但也不会造成什么影响」,那你真是大错特错了。

使用 JWT 作为 Session 机制存在很多缺点,其中一部分会造成严重的安全问题。

更费空间

JWT Tokens 实际上并不「小」。尤其是使用无状态 JWT 时,所有的数据将会被直接编码进 Tokens 内,很快将会超过 Cookies 或 URL 的长度限制。你可能在想将它们存储到 Local Storage,然而...

更不安全

若将 JWT Tokens 存储到 Cookies 内,那么安全性与其他 Session 机制无异。但如果你将 JWT 存储至其它地方,会导致一个新的漏洞,详见本文,尤其是「Storing sessions」这一部分。

书接上回:Local Storage,一个 HTML5 内很棒的功能,使浏览器支持 Key/Value 存储。所以我们应当将 JWT Tokens 存储到 Local Storage 吗?考虑到这些 Tokens 可能越来越大,或许会很有用。Cookies 通常在 4k 左右的存储时比较占优势,对于较大的 Tokens,Cookies 可能无法胜任,而 Local Storage 或许成了明确的解决方案。然而,Local Storage 并没有提供任何类似 Cookies 的安全措施。
LocalStorage 与 Cookies 不同,并不会在每次请求时发送存储的数据。获取数据的唯一方法是使用 JavaScript,这意味着任何攻击者注入的 JavaScript 脚本只需通过内容安全策略检查,就能任意访问或泄露数据。不光是这样,JavaScript 并不在意或追踪数据是否通过 HTTPS 发送。就 JavaScript 而言,它就只是个数据而已,浏览器会像操作其它数据一样来处理它。
在历代工程师们经历了各种麻烦之后,终于能够确保没有人可以恶意接触到我们的 Cookies,然而我们却试图忽略这些经验。这对我来说似乎是在退步。

简单来说,使用 Cookies 并不是可选的,无论你是否采用 JWT。

无法单独销毁

还有更多安全问题。不像 Sessions 无论何时都可以单独地在服务端销毁。无状态 JWT Tokens 无法被单独的销毁。根据 JWT 的设计,无论怎样 Tokens 在过期前将会一直保持有效。举个例子,这意味着在检测到攻击时,你却不能销毁攻击者的 Session。同样,在用户修改密码后,也无法销毁旧的 Sessions。

对此,我们几乎无能为力,除非重新构建复杂且有状态(Stateful)的基础设施来明确地检测或拒绝特定 Session,否则将无法结束会话。但这完全违背了使用无状态 JWT Tokens 的最初目的。

数据延迟

与上文的安全问题类似,还有另一个潜在的安全隐患。就像缓存,在无状态 Tokens 内存储的数据最终会「过时」,不再反映数据库内最新的数据。

这意味着,Tokens 内保留的可能是过期的信息,例如:用户在个人信息页面修改过的旧 URL。更严肃点讲,也可能是个具备 admin 权限的 Token,即使你已经废除了 admin 权限。因为无法销毁这些 Tokens,所以面对需要移除的管理员权限,除非关闭整个系统,别无他法。

实现库缺乏生产环境验证或压根不存在

你或许在想,以上的这些问题都是围绕着「无状态 JWT」展开的,这种说法大部分情况是对的。然而,使用有状态 Tokens 与传统的 Session cookies 基本上是等效的... 但却缺乏生产环境的大量验证。

现存的 Session 实现(例如适用于 Express 的 express-session)已经被用于生产环境很多很多年,它们的安全性也经过了大量的改良。倘若使用 JWT 作为 Session cookies 的临时替代品,你将无法享受到这些好处,并且必须不断改进自己的实现(在此过程中很容易引入漏洞),或使用第三方的实现,尽管还没有在真实世界里大量应用。

译者注:实际上,Laravel Passport 便是使用类似「有状态 JWT」的方式来存储 OAuth Access Token。幸运的是,Passport 已经有不少实际应用,且不完全依赖于 JWT。

结论

无状态 JWT Tokens 无法被单独地销毁或更新,取决于你如何存储,可能还会导致长度问题、安全隐患。有状态 JWT Tokens 在功能方面与 Session cookies 无异,但缺乏生产环境的验证、经过大量 Review 的实现,以及良好的客户端支持。

除非,你工作在像 BAT 那样规模的公司,否则没什么使用 JWT 作为 Session 机制的理由。还是直接用 Session 吧。

所以... JWT 适合做什么?

在本文之初,我就提到 JWT 虽然不适合作为 Session 机制,但在其它方面的确有它的用武之地。该主张依旧成立,JWT 特别有效的使用例子通常是作为一次性的授权令牌。

引用 JSON Web Token specification

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. [...] enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.

在此上下文中,「Claim」可能是一条「命令」,一次性的认证,或是基本上能够用以下句子描述的任何情况:

你好,服务器 B,服务器 A 告诉我我可以 < ...Claim... >,这是我的证据:< ...密钥... >。

举个例子,你有个文件服务,用户必须认证后才能下载文件,但文件本身存储在一台完全分离且无状态的「下载服务器」内。在这种情况下,你可能想要「应用服务器(服务器 A)」颁发一次性的「下载 Tokens」,用户能够使用它去「下载服务器(服务器 B)」获取需要的文件。

以这种方式使用 JWT,具备几个明确的特性:

  • Tokens 生命期较短。它们只需在几分钟内可用,让客户端能够开始下载。
  • Tokens 仅单次使用。应用服务器应当在每次下载时颁发新的 Token。所以任何 Token 只用于一次请求就会被抛弃,不存在任何持久化的状态。
  • 应用服务器依旧使用 Sessions。仅仅下载服务器使用 Tokens 来授权每次下载,因为它不需要任何持久化状态。

正如以上你所看到的,结合 Sessions 和 JWT Tokens 有理有据。它们分别拥有各自的目的,有时候你需要两者一起使用。只是不要把 JWT 用作 持久的、长期的 数据就好。

本作品采用《CC 协议》,转载必须注明作者和本文链接
Former WinForm and PHP engineer. Now prefer Golang and Rust, and mainly working on DevSecOps and Kubernetes.
本帖由系统于 5年前 自动加精
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 65
Mangou

JWT 在作为session时 , 自动续期和指定失效 2个方面是致命伤。

laravel passport 还有维护token黑名单这种操作。为了用而用。。。

5年前 评论

@Flourishing

目前来说,我博客使用的是 Hexo + indigo 主题。

另外涉及到几个点:

5年前 评论
Mangou

JWT 在作为session时 , 自动续期和指定失效 2个方面是致命伤。

laravel passport 还有维护token黑名单这种操作。为了用而用。。。

5年前 评论

可以大概讲讲你的博客的架构吗? 我想做一个类似的博客站点

5年前 评论

@Flourishing

目前来说,我博客使用的是 Hexo + indigo 主题。

另外涉及到几个点:

5年前 评论

好文章,不错。

5年前 评论

如何作废已颁发的JWT确实是个问题

5年前 评论
zgxxx

一些无法使用cookie的场景还是得用JWT的,像第三方接口,例如小程序开发我就是用jwt

5年前 评论

@zgxxx

很多人错误地尝试比较 Cookies 和 JWT。这种对比毫无意义,就像对比内存和硬盘一样。Cookies 是一种存储机制,然而 JWT Tokens 是被加密并签名后的令牌。
它们并不对立 —— 相反,他们可以独立或结合使用。正确的对比应当是:Session 对比 JWT,以及 Cookies 对比 Local Storage。
在本文中,我将把 JWT Tokens 同 Session 展开对比,并偶尔对比 Cookie 和 Local Storage。这样的比较才有意义。

建议认真阅读。

5年前 评论
zgxxx

@Wi1dcard “一些无法使用cookie的场景还是得用JWT”,这里并没有比较cookie和JWT,session最终也是归到cookie里面,只不过服务器客户端问题

5年前 评论

@zgxxx JWT 是一种存储介质,无法使用 Cookie 的场景,例如你说的微信小程序,照样可以使用 Local Storage,那么照样可以存储 Session ID,这完全不需要 JWT。同样,你使用 JWT 照样可以将它的 Token 存储在 Cookies 内,你根本没有搞清楚这几个东西的关系。

5年前 评论

@Will

使用token传递识别身份,难道有错了。。微信开放平台不是也是key与secret换取ticket.然后获取token吗。续期可以使用refreshtoken进行刷新,刷新后 之前的token(没有过期的)可以放在黑名单中,然后过期也自动失效了。

辩:JWT Tokens 不等于 Tokens。你这里说的 Tokens 是 OAuth 机制内的 Tokens,跟 JWT 无关,请你搞清楚再来反驳。

比如禁用cookie.可以把生成的JWT放在头信息。或者放在QueryString中。只是使用token .至于怎么携带 是使用cookie携带、还是使用自定义的http头部携带。这个都不是问题。。你可以反驳说可以把类似的session_id PHPSESSID 放在QueryString 和自定义的头部一样,JWT只是多了一种http上下文生成唯一标示符号token多了一种实现。

辩:把 Token 放在 QueryString 或自定义 HTTP 头内发送,也就意味着必须将 Token 存储到 LocalStorage 或其它地方,那么原文已经解释过会出现另一种漏洞:若将 JWT Tokens 存储到 Cookies 内,那么安全性与其他 Session 机制无异。但如果你将 JWT 存储至其它地方,会导致一个新的漏洞,详见本文,尤其是「Storing sessions」这一部分。

你翻译一篇文章 就反驳所有的。这篇文章也只是作者的建议。

辩:英文水平好可以去看原文,原作者的语气自己揣摩。或许我翻译的不好,你也可以来翻译或者改进。对吧。

最后,不服欢迎辩论,但不要引战,就像原文在最初提到的:

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

5年前 评论

@Will

如果JWT极端使用。。就可以放在每个链接上(或者说每个api中),鉴权完后下发token,每个需要授权的链接都带上JWT的QueryString(或者http头部的某个key).服务端在QueryString(或者http头部的某个key)获取到这个token.然后在返回token .客服端自动拼接token到QueryString(或者http头部的某个key)中。这样就可以不需要保存token而在每次请求中带上这个token。虽然并不推荐这样做,这样做也不好,但是也可以做到本地不保存token,而在每个需要带上token的地方使用token,万事无绝对。

辩:也就是说,你将 Token 拼接为 URL 直接下发给客户端,那么通过 JavaScript 照样能够读出来 Token 值,并且可以被另作他用。恶意代码攻击依旧可行。

有说微信的token就是JWT...呵呵。。

辩:请仔细阅读我的观点,另外请纠正你的错别字。

比如:服务器之间的鉴权交互(分布式系统之间的交互等),不一定JWT一定就要使用客户端、服务端的交互,通过鉴权后生成JWT,token就可以放在服务端,不一定非要什么cookie LocalStorage,可以放在服务端任何可以存储的地方,比如redis、内存等。

辩:是的,无论是我还是原文作者,都没有彻底贬低 JWT,在本文最初和结尾都有强调「JWT 在其它方面有合适的用武之地,它只是不适合作为 Session 机制」,本文标题也是「请勿使用 JWT 作为 Session 机制」。而且结尾,作者也推荐了与你描述的这种用途类似的场景。请你仔细阅读完本文,练习好自己的表达能力和理解能力,再发表你的观点。

不再辩解,你说的都有理。谢谢~~

可笑。

5年前 评论

@史沟飞 想作废还是有多方法的。jwt配合服务器产生登录用户名单,服务端删除需要重新登录校验不就可以了。或者指定过期时间,之后拿到密码从新生成token,不一致就过期呗。

5年前 评论

@Rain 是的,但请注意这一句:

对此,我们几乎无能为力,除非重新构建复杂且有状态(Stateful)的基础设施来明确地检测或拒绝特定 Session,否则将无法结束会话。但这完全违背了使用无状态 JWT Tokens 的最初目的。

5年前 评论

@Flourishing 没有后端,纯静态,使用 Hexo 作为静态站点生成器渲染出的 HTML。

如果想要 Laravel 的 Blog,并且喜欢定制学习的话,推荐一个我同事的 Repo:https://github.com/baijunyao/laravel-bjybl...

5年前 评论
萧瑟秋风 4年前

@Wi1dcard 谢谢你的分享 功能还是很丰富的,就是看起来样式不是那么炫酷

5年前 评论

@Flourishing 所谓 Functional beauty,哈哈。

5年前 评论
yourself

挺好的,jwt什么的其实并不是重点。使用技术完全取决于你的公司,但是技术选型一些周边技术分析的考虑因素这才是关键。例:优势,缺点,安全性,使用场景

5年前 评论
巴啦啦

我在做安卓后端的时候,我有过这样的做法。在laravel中做两个中间件,一个是响应颁发token,一个是收到请求验证token。响应时,自动续时token。收到请求时,验证token是否正确,有没有过期。我是这么实现token的。

实现一个数组,数组内包含用户基本信息和过期时间戳。然后转换为json,json后面拼接一个env文件里的自定义的串。

最后将串通过某种自定义的编码方法转换为一个看起来无意义的串(这个编码方法里面也会有env文件里的自定义串)。对应的还有解码方法。编码和解码都做成了一个trait,分别在进出两个中间件中使用。

我觉得还是session香。

5年前 评论

那不对哦,文中说了很多Storage+jwt 不如cookie+session, 但是app没cookie的

5年前 评论

@gangpula 谁说 App 不支持 Cookies。

5年前 评论
panda-sir

说下我的观点: 更费空间 : 我在设计jwt token存储的时候 只存入了关键信息 无状态token不代表 需要存入用户所有基本信息
无法单独销毁: 我将token 按找一定的规律存储在我的redis 中 可以达到随时销毁的目的 销毁后 虽然前端cookie内存储的token没有销毁 但当用户再次访问系统的时候 api会抛出对应的状态码 并没有你说的无法单独销毁的问题 主要看你怎么设计存储token
数据延迟 : 你在文中提的这个权限的token例子很有代表性 但我只能说明 我使用jwt token 的时候只是为了维持用户登录状态 权限信息是根据token内解析的用户id获取的 token的就算不销毁 对应用户的权限一旦关闭 你也没法进入对应的系统或者模块的
实现库缺乏生产环境验证或压根不存在: 这个嘛 勇于尝试 发现问题 解决问题 才能让这项技术让更多的人知晓
最后再提一句 防止csrf_token 攻击是你需要将token以 http请求首部发送 而不是存到cookie然后发送 默认浏览器都会携带cookie 你只要不使用前端传递的cookie 使用跟前端约定的http首部字段 就可以避免csrf_token问题 因为你已经不使用cookie了

5年前 评论

@panda-sir

我将token 按找一定的规律存储在我的redis 中 可以达到随时销毁的目的 销毁后 虽然前端cookie内存储的token没有销毁 但当用户再次访问系统的时候 api会抛出对应的状态码 并没有你说的无法单独销毁的问题 主要看你怎么设计存储token

将 Token 写入 Redis,首先这个操作就完全丧失了 JWT 存在的意义,与 Session 机制无异。且 JWT 的 Token 通常会比传统 Session ID 更加长,而你这个方案还需要在客户端和服务端「同时」存储这个比较长的 Token。虽可行,但也只能算是折中吧,跟维护一份 Token 黑名单类似。

使用跟前端约定的http首部字段

那就导致你需要将 Token 存储到类似 Local Storage 的地方,因此又引发了另一个漏洞,在文中有说明。

5年前 评论
panda-sir

@Wi1dcard 受教了 查了查资料
清空或修改服务端的用户对应的 secret,这样在用户注销后,jwt 本身不变,但是由于 secret 不存在或改变,则无法完成校验。这也是为什么将 secret 设计成和用户相关的原因。
仔细看了下 感觉也不能解决无法销毁Token的问题, 当用户在多个终端或者 单个终端多个浏览器登录的时候, 会因为改变用户的secret使得所有终端或者所有Token都失效, 是否有更好的办法呢 如果对Token不存储在服务端的话

5年前 评论

@panda-sir 是的,会直接全部失效。

至于完全无状态(即服务端完全没有 Token 等运行时写入的数据),个人认为比较难。可以考虑 Kubernetes 等,将应用服务独立出来无状态,便可随时横向扩展集群;而 Session 服务由独立的 Redis 集群等提供。

5年前 评论
panda-sir

@Wi1dcard :crying_cat_face: 这还是session 存储服务端管理登录状态 按照jwt设计的初衷来讲 不存储服务端的话 , 感觉也许这就是http吧

5年前 评论
guanhui07

好文。

5年前 评论
hookover

无法销毁应该是有替代手段的,比如二次校验
或者增加用户的个人KEY到算法中,修改密码的同时重置该KEY即可

5年前 评论

新手请教,不用jwt的话前后端分离项目怎么做呀,前后端不同域名,怎么用session呢?
前端把接口返回的sessionid保存到cookie里么?那这样的话ajax访问后端接口会自动带着cookie里的数据访问(sessionid)接口吗?

  • -,新手一枚真心不懂木有头绪,望高手大大们不吝赐教,帮我详细说一下哈。。学习ing~!!
5年前 评论

@hookover 按照你的想法,这样需要每次请求都验证一遍这个假定的 Key,那么该 Key 存储在哪里呢?数据库吗?那与「每次请求验证用户密码」有什么本质上的区别呢?

5年前 评论

@牛牛小宝 前后端不同域名并不影响 Session。只要 确保签发 Session ID 时的域名请求后端时 的域名一致,浏览器会自动将存储在 Cookies 内的 Session ID 携带并发送。

5年前 评论

我个人觉得session本身存在的意义不大,尤其在如今前后端分离成为趋势的情况下。

5年前 评论

@Wi1dcard 感谢回答。这个问题大概明白了,ajax请求时设置withCredentials=true就可以跨域携带cookie信息了。
那如果像小程序没有cookie怎么处理sessionid的传递呢?

5年前 评论

@牛牛小宝 我个人猜测小程序禁止 Cookies 的存在是为了避免大量无用 Cookies 的存在拖慢请求速度。至于如何解决这个问题,我对小程序的具体内部机制不太清楚,不过依稀记得似乎是采用 LocalStorage 来解决这个问题,在每次请求的时候手动带上 SessionID(或者是 Token)。实际上因为小程序并不是标准的浏览器环境,我猜微信对小程序有进行特殊的隔离处理,所以存储在 LocalStorage 内的数据 应该 是安全的。

5年前 评论

@Rain 感觉这样的话就几乎是自己实现了一遍 session。

5年前 评论

请教作者,如果我在 app 里需要访问API , 在鉴权方面,我们之前用的是 JWT token,您觉得是否合适?如果不合适,应该用什么?请指条明路!谢谢

5年前 评论

两者的使用场景不尽相同,jwt跟session并不一样

5年前 评论

@andyzu 我不是本文原作者,所以无法提供技术支持。不过,依照原文作者的看法,还是使用原始的 Session 比较合适,没必要 JWT。你也可以试试 Laravel Passport 的方式,下发 OAuth Access Token。

5年前 评论

@WilliamMa 是的,原文作者也想表达这个想法,场景不同,不应该把 JWT 作为 Session 机制。

5年前 评论

@史沟飞 我觉得可以在服务器用缓存把jti存储起来,验证的时候在比对一下jti就可以了

5年前 评论
LivisSnack

JWT机制还是很危险的,通过抓包工具就可以轻易获取到认证token值。而有些APP的token值过期时间设置很长(例如某某打卡软件--过期时长长达一年),就可以各种模拟请求了!

5年前 评论

@LivisSnack 这跟 JWT 无关。其它 Session 机制,只要是基于 HTTP 协议,或者说只要有通讯,都可以被抓出来。所以才需要 HTTPS~

5年前 评论
LivisSnack

@Wi1dcard https也一样抓的!

5年前 评论

@LivisSnack 那是因为你在你的机器上信任了抓包工具提供的证书。这叫做 MitM「中间人攻击」,客户端不信任证书的话,是无法解密 HTTPS 流量的。

5年前 评论

@Flourishing 推荐给你一个laravel5.8支持markdown的开源博客 VienBlog

5年前 评论
耐小心

所以如果要做API 不建议使用JWT 而是使用session? 然后使用ip_hash或者是redis来保证登录态的同步?

5年前 评论

@耐小心 API 为什么一定要牵扯到会话(所谓登录态)同步?

5年前 评论
lmaster

@Wi1dcard 哇,白俊遥是你同事,很早以前就关注了他的 tp-blog,貌似转 laravel 后就不更新了

5年前 评论
lmaster

事,不说不清;理,不辩不明。
我的高中英语老师一直强调,翻译要做到:信、达、雅。
其中,求其信,已大难矣。译文要准确,不偏离,不遗漏,也不要随意增减意思。
所以,本文是难得好的译文,同时也是好的论帖。

已赞,已收藏
最后声明,不论谁对谁错,本人对参与讨论者都表示尊敬。在学习的路上本就寂寞,若没有争执与讨论更加凄凉。

5年前 评论

嗯 还在尝试中 个人还是喜欢用jwt来做认证

5年前 评论

@lovecn 我的博客链接做过一次升级,之前是 https://wi1dcard.cn/分类名/文章简称/ 后来统一为 https://wi1dcard.cn/posts/文章简称。因此你可以将中间的分类名(例如 wtfdocumentstutorials 等)替换为 posts 即可访问。感谢关注!

4年前 评论

@lovecn 评论内的原链接已替换为新链接,可以直接访问啦。

4年前 评论
medz

个人一直使用 JWT 其实是因为 jwt 方便,我解决当个用户的 token 情况是,自定义编码用户内容,大多数人仅编码一个 user id 进去,我在用户表有一个 token_salt,其作用是用户修改密码这类操作的时候修改数据库的 salt,这样旧 token 达到无法验证通过的效果。强下限某一个用户的所有 token 也是修改盐值。有一个弊端,就是用户在客户端修改密码后,当前 token 不可用了,我的解决方法是用户修改密码后返回一个新的 jwt token 供后续使用。看如何使用了理解吧。原文我看了,说的是比较初阶的使用方法。jwt 的扩展性个人理解也提现在这里。可以通过很多方法进行处理。毕竟在自定义信息阶段仅使用已有工具包默认方式,确实很不安全。其实就是看怎么用吧。

4年前 评论
medz

我所谓的 jwt 方便,不要误解,而是在实现后交互上的方便。我的大多数开发场景不涉及到 web 端。oauth2 则不那么方便。而且我一直不用 oauth2 的原因是 b2c 场景下,即使是密码模式也需要 client id 这类信息,生成一条放在服务端,然后客户端传递用户账号密码来生成 token 有点脱了裤子放屁的感觉。oauth2 个人感觉适用 b2b 场景。

4年前 评论

个人一直使用jwt,其实不能说jwt
个人理解的,cookie保存session_id,然后后端通过session_id获取具体的session信息
我的jwt是,LocalStorage保存一个随机字符串的token,然后后端通过token查找具体的信息
session注销也只是让后端的session信息失效,并不能让cookie里面的session_id失效,只是session_id对应的信息失效了
那token也一样,token还是有效的,只是token对应信息失效了
token的适用场景更广泛,定制性更强,如果多个项目共享用户状态也更容易实现

4年前 评论

题目说的是“别再使用 JWT 作为 Session 系统”,简单来说怎么保持登录状态。为什么要保持登录状态,是因为HTTP是短连接,登录之后连接已经断开无法知道下次连接上一次连接的关系,从而无法保持登录状态。我们为了保持连接使用Cookie机制,Cookie其实简单来说是保存数据用的,我们可以把连接状态保存到数据里。由于Cookie可以从服务器读写(Cookie机制浏览器实现),所以往往我们登录登出都是有服务器控制,简单来说客户端无感知,不需要前端做什么。这个机制一直运行比较好,直到出现了APP时代,我们的程序不仅仅在浏览器上实现,我们的程序也需要支持本身的app开发,但是由于Cookie是W3C的标准不是HTTP的标准,而APP本身不支持Cookie为了解决这个问题才出现了Token的机制,JWT本身就是这样一个机制。Token机制本身是灵活的,不依赖于Cookie,他可以存在任何地方,内存中,LocalStorage,Cookie,文件等等,所以简单来说Token更灵活更广泛,而且它只是解决保持登录的一种机制而已,至少现在来看,它比较适合现在应用程序的开发。我觉得博主上面的比较有点太注重细节,你说的那些比较事实上都不是很么致命的问题,都是可以通过程序去避免的,这些比较都不能说使用Token这种机制有什么不好。

4年前 评论
Wi1dcard (楼主) 4年前

我想了解一下微信开放平台的授权验证有用到哪些协议 比如已知的oauth2.0 授权 openid 还有其他的吗?

3年前 评论

认真看完了以后,觉得某些观点过于主观,我觉得 Token 和 Session ID 一样,提供一种承载身份认证的可能,需不需要无状态取决于是否需要撤销 Token,你想安全一点可以在后端用各种方式去让某个 Token失效,Session 不也是这样么。

将 JWT 向 Session 一样使用是一种方案,比 Session 更灵活,它是渐进式的,可以无状态,也可以有状态,而 Session 是一步到位。

我相信绝大多数后端都是将角色和权限等与用户关联,而是不是 Token,所以是否真的存在数据延迟,还得看怎么用 JWT!换句话说如果用同样的方式(将用户角色与权限放到 Cookie 中)去使用 Cookie + Session 也存在同样的问题。

3年前 评论

好文章。。对区分JWT,Session更加清晰了。。感谢分享。。一直在纠结接口使用session还是jwt纠结。。

3年前 评论

我来说说我的看法吧

session是以前jsp或者其他后端代码混合时代,服务端渲染时服务端用来检测会话用户的凭证吧,一般是sessionId.

而现在前后端分离的模式,和多端兼容的需求,sessionId的模式已经不大适用了,然后就有了token的一样个验证模式。

token验证模式使用比较广泛的就是jwt,当然你也可以自己写一个自己的token来判断,还有个情况就是把以前的sessionId作为token,至于哪种好根据自己的业务去判断。

jwt有优势是一个无状态,但安全性的话有些缺陷。

jwt如果追求个绝对的安全,那肯定是要做成有状态的,可控的,这完全没问题的。

jwt有无状态都可以,根据自己业务去处理,无可厚非。当然你就要用sessionId也行,符合自己的业务就行

2年前 评论

jwt 这玩意只是他封装了一个生成token的方法吧 我完全可以自己生成吧 可以简单这么理解吧 毕竟任何不基于服务器控制的token都不是好token 他无非就是客户端去存 自己去解而已 但是实际运用都结合到redis吧 既然用到redis了 我不如自己生成token算啦

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
67
粉丝
590
喜欢
1235
收藏
1133
排名:13
访问:32.4 万
私信
所有博文
社区赞助商