Session
快来分享你的内容吧~
- 06-30 13:15·@编程小助手 微信: leikooo_一句话结论:JWT 不适合用来维持用户登录状态。 它本来就不是为持久会话设计的;真正干这件事的工具,是服务端 Session + Cookie,而且这套方案已经用了几十年。 先把概念对齐。很多人把「Cookie vs JWT」拿来对比,这本身就不对——查看全文leikooo:最近看到两篇文章感觉对又重新认识了 JWT😋,http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/、https://gist.github.com/samsch/0d1f3d3b4745d778f78b230cf60614529510分享
- 2023-12-12·后端浅谈session和cookie 最近写了好多次登录注册的业务接口,那不免会听到session、cookie等概念。那么他们是什么呢?之间的关系?有啥作用呢?我这次终于好好捋清楚他们的关系了,这次做一次学习总结。 背景 先讨论Session和Cookie,我们先了解其诞生的背景,毕竟需求推动技术的! 基于以前的互联网的网络协议的请求是HTTP(无状态的网络请求协议),意味着每个单独的请求之间是相互查看全文编程导航_小y:知识碎片的目的是通过简单分享,帮大家快速学习重点编程小知识。知识碎片汇总:https://yuyuanweb.feishu.cn/wiki/AqfawFUT0iD69kkiRKoci6Nqnqc欢迎参与贡献,获取奖励:https://docs.qq.com/form/page/DQkdHTGFLQmJjV3VU#/fill2630分享
别用 JWT 管理用户会话
> 参考:[Stop using JWTs!](https://gist.github.com/samsch/0d1f3d3b4745d778f78b230cf6061452)(samsch) --- 一句话结论:**JWT 不适合用来维持用户登录状态。** 它本来就不是为持久会话设计的;真正干这件事的工具,是服务端 Session + Cookie,而且这套方案已经用了几十年。 先把概念对齐。很多人把「Cookie vs JWT」拿来对比,这本身就不对——Cookie 是**存储/传输机制**,JWT 是**带签名的令牌格式**,两者不是对立关系。真正该比的是: - **无状态 JWT**:会话数据直接编码进 Token 里 - **有状态 JWT**:Token 里只放一个 Session ID,数据仍在服务端 - **传统 Session Cookie**:一个(可选签名的)Session ID,数据同样在服务端 本文不是说 JWT 永远不该用,而是:**别把它当会话机制。** 那样做既不合适,还有安全隐患。 ## 常见误区 **「无状态更好扩展」**——只有无状态 JWT 在技术上才略沾边,但绝大多数应用根本到不了那个规模。单机多进程用 Redis 存 Session,多机再挂一台 Redis,现有框架都支持得很好。真到了要换方案的时候,全员登出一次就能迁移,不值得为了「未来可能」提前背上 JWT 的坑。 **「JWT 更简单、更灵活、更安全」**——恰恰相反。框架自带的 Session 开箱即用;灵活度上 Session 本来就能存任意数据;安全上,好的 Session 实现同样会用签名 Cookie,「用了密码学」不等于更安全。把 JWT 塞进 Local Storage 反而更危险——任何能执行 JS 的 XSS 都能把 Token 读走,而 HttpOnly Cookie 天生防这个。 **「JWT 自带过期,不用管 Session 清理」**——服务端过期同样好做,而且能在过期时清理数据库里的 Session 数据;无状态 JWT 过期前服务端毫无办法。 **「用 JWT 就不用 Cookie 同意弹窗」**——错。法规管的是**持久标识符**,跟你怎么存无关。功能性登录态本来就不需要额外同意;追踪分析才需要,换 JWT 也逃不掉。 **「放 Local Storage 能防 CSRF」**——CSRF 要靠 CSRF Token 防,跟 Session 机制无关。JWT 放 Cookie 一样有 CSRF;放 Local Storage 则强依赖 JS,还引入 XSS 风险。正确的 CSRF 缓解只有一种:**CSRF Token**。 **「移动端/禁 Cookie 用户更适合 JWT」**——移动浏览器和 HTTP 客户端都支持 Cookie;禁 Cookie 的用户通常也会禁 Local Storage。后端对移动端和 Web 端可以同一套 Session,Cookie 对 HTTP 客户端来说就是普通请求头,每次带上即可。 ## 真正的代价 **体积大。** 无状态 JWT 把用户信息全塞进 Token,很容易顶破 Cookie 4KB 上限,被迫改用 Local Storage——然后回到上面的安全问题。 **无法单独作废。** Session 可以随时在服务端踢掉;无状态 JWT 在过期前永远有效。用户改密码、发现账号被盗、撤销管理员权限——你都没法立刻让旧 Token 失效,只能等它自然过期,或者自己搭一套「黑名单」基础设施,那「无状态」也就名存实亡了。 **数据会过期。** Token 里的角色、权限、资料都是签发那一刻的快照。用户刚被降权,手里还攥着写着 `admin` 的旧 Token,而你又作废不了它。 **实现欠打磨。** 有状态 JWT 本质上就是 Session Cookie 的劣化版——功能一样,却少了 express-session 这类久经沙场、反复修漏洞的实现。自己撸一套,很容易踩坑。 JWT 规范本身也饱受安全圈质疑:早期甚至允许 `alg: none` 伪造 Token,整体设计面向的是**极短寿命**(大约 5 分钟以内)的凭证,不是长登录态。 ## 那 JWT 适合什么? 适合**一次性、短时效的授权凭证**,而不是持久会话。典型场景: - 文件下载:应用服务器验证登录后发一个几分钟有效的下载 Token,无状态的下载服务器验签后直接吐文件 - 单点登录中转:Google 浏览器里用的是普通 Cookie Session;JWT 只在跨服务传递「刚登录成功」这一下,随后各产品各自建 Session - 微服务内部:网关验完 Session 后,用短寿命 Token 在内部服务间传递身份,避免每个服务都查一遍 Session 库——但即便这里,内网 API Key + 明文传用户 ID 往往也够,未必非 JWT 不可 好的 JWT 用法有几个共同点:**短命、单次或极少次使用、应用本身仍用 Session 管登录。** ## 该怎么做 直接用框架自带的 Session。对于 Javaer 来说 SpringBoot 封装的非常好,引入几个依赖写几行代码就搞定了,如果想要保存到 Redis 也是引入一个依赖的事情,非常方便! ## 总结 Cookie 是旧技术,但旧不等于差。安全领域,**久经考验、没被打穿**,往往比「新且未经充分检验」可靠得多。 Session 和 JWT 可以并存,各干各的——只是别把 JWT 当长期登录凭证。 用户登录这件事,交给 Session 就好。
浅谈Cookie和Session
<html> <head></head> <body> <div class="content ql-editor"> <p><br></p> <h1><strong style="color: rgb(51, 51, 51);">浅谈session和cookie</strong></h1> <p><br></p> <p>最近写了好多次登录注册的业务接口,那不免会听到session、cookie等概念。那么他们是什么呢?之间的关系?有啥作用呢?我这次终于好好捋清楚他们的关系了,这次做一次学习总结。</p> <p><br></p> <h2><strong style="color: rgb(51, 51, 51);">背景</strong></h2> <p>先讨论Session和Cookie,我们先了解其诞生的背景,<strong>毕竟需求推动技术的</strong>!</p> <p>基于以前的互联网的网络协议的请求是HTTP(无状态的网络请求协议),意味着每个单独的请求之间是<strong>相互独立、互不相关</strong>的,服务器在处理一个请求后并不会保存任何关于客户端状态的信息。这样带来的弊端就是服务端无法判断客户端发来的请求是哪个用户发起的,因此我们就需要对<strong>状态保持进行额外处理</strong>,这就诞生了Cookie和Session。</p> <p><br></p> <h2><strong style="color: rgb(51, 51, 51);">Cookie</strong></h2> <h3><strong style="color: rgb(51, 51, 51);">概念</strong></h3> <p>Cookie(HTTP Cookie)是由服务器(服务端)发送到用户浏览器(客户端)并保存在用户本地计算机上的<strong>小型文本文件</strong>(可持久化)。Cookie 用于存储特定网站的用户信息(状态保持),以便在用户访问同一网站时可以检索和使用这些信息。</p> <p><br></p> <h3><strong style="color: rgb(51, 51, 51);">应用场景</strong></h3> <p>概念似乎晦涩难懂,以一些应用场景举例,就可能体察到Cookie的存在啦</p> <ol> <li data-list="ordered"><span class="ql-ui"></span>用户登录,存储账号密码</li> </ol> <p>这个就必须是<strong>首次登录成功后</strong>,浏览器会提示用户是否要保存账号信息,这个本质就是通过Cookie进行用户信息的存储,下次就可以直接免登陆操作了。</p> <blockquote> <div class="blockquote-item"> PS:免登陆不是说不用通过数据库查询,而是下次登录的信息从Cookie中取出。 </div> </blockquote> <p><span class="ql-font-monospace"> </span><img src="https://pic.code-nav.cn/planet_post_image/1620599227736473602/3uhlwmdp.jpeg"></p> <p>2. 会话管理</p> <p>用于检测用户是否在网站登录后有进行连续操作(访问网站资源),否则超过过期时间,则会消失,即用户就得重新校验身份。例如:哔站登录后不作任何操作,30天过需要重新登录。</p> <p>3. 个性化体验</p> <p>这种存储个人偏好配置,采用的方案之一就有是Cookie进行的。个人偏好配置比如:暗黑模式,页面布局、语言选择等等。</p> <p><br></p> <h3><strong style="color: rgb(51, 51, 51);">作用</strong></h3> <p>通过上面的介绍,Cookie的作用也应该已经呼之欲出了!这里还是总结一下~</p> <ol> <li data-list="bullet"><span class="ql-ui"></span>服务器识别用户,保持用户在跳转页面时会话状态的一致性。</li> <li data-list="bullet"><span class="ql-ui"></span>实现免登陆,自动进行身份验证</li> <li data-list="bullet"><span class="ql-ui"></span>保留个性化体验</li> </ol> <p><br></p> <h3><strong style="color: rgb(51, 51, 51);">存储位置</strong></h3> <p>既然Cookie是存储在本机的小型文本,那么它具体存储在哪里呢?</p> <p>答:不同的浏览器和不同的操作系统,Cookie存储本机的位置都是不同的。见下图(Chatgpt如是说)</p> <p><span class="ql-font-monospace"> </span></p> <p><img src="https://pic.code-nav.cn/planet_post_image/1620599227736473602/n37ftjgw.jpeg"></p> <h2><strong style="color: rgb(51, 51, 51);">Session</strong></h2> <p>Session的中文名是会话,Session和Cookie可谓是“黄金搭档”,有了Cookie就一定有Session。</p> <p><br></p> <h4><strong style="color: rgb(51, 51, 51);">概念</strong></h4> <p>会话(Session)是指在用户与服务器<strong>(服务端)</strong>之间建立的一个交互周期。它允许服务器跟踪用户在一系列请求和响应之间的状态,从而实现一定程度的状态保持。意思就是我们常说的Session是存在于服务端的一个概念,用于跟踪用户的请求和响应。</p> <p>问题:</p> <ol> <li data-list="ordered"><span class="ql-ui"></span>浏览器的Cookie里面也有session,和服务端的Session的区别是什么?</li> </ol> <p>答:前者的Session又称之为<strong>会话Cookie</strong>,他是属于浏览器进程中Session,一旦关闭浏览器,会话Cookie就会被杀死,因此是<strong>不具持久化</strong>的;后者的<strong>Session</strong>是创建于服务端,他可以<strong>被持久化</strong>,可以存储多个地方,如:内存,磁盘等。</p> <p><br></p> <h4><strong style="color: rgb(51, 51, 51);">Cookie和Session的关系</strong></h4> <p>我以关系图来表示,这样显得更直观。</p> <p><span class="ql-font-monospace"> </span></p> <p><img src="https://pic.code-nav.cn/planet_post_image/1620599227736473602/ht3vkt25.jpeg"></p> <p><br></p> <h4><strong style="color: rgb(51, 51, 51);">Session的生命周期</strong></h4> <p>这里就得要分类讨论了,浏览器的Session(会话Cookie)和服务端的Session的生命周期是不一样的。</p> <ol> <li data-list="bullet"><span class="ql-ui"></span>会话Cookie:浏览器端的 Session 存储在用户的浏览器中,通常在<strong style="font-family: inherit; font-size: inherit;font-style;font-variant-ligatures;font-variant-caps;">用户关闭浏览器时结束</strong>。这种 Session 只在用户的当前浏览器窗口或标签页内有效。当用户关闭浏览器时,浏览器通常会清除与该 Session 相关的 Cookie 数据。</li> <li data-list="bullet"><span class="ql-ui"></span>Session:服务端的 Session 存储在服务器上,其<strong style="font-family: inherit; font-size: inherit;font-style;font-variant-ligatures;font-variant-caps;">生命周期通常由服务器的配置来控制</strong>。服务端的 Session 可以在用户的多个请求之间保持状态,而不受用户关闭浏览器的影响。</li> </ol> <p>问题:</p> <ol> <li data-list="ordered"><span class="ql-ui"></span>不同用户在同一个浏览器同一个标签页发起同一个请求,sessionId相同吗?</li> </ol> <blockquote> <div class="blockquote-item"> 是相同的,但这样当前的session的value会被下一个请求的session的value覆盖。(前提是session的key是相同的) </div> </blockquote> <ol> <li data-list="ordered"><span class="ql-ui"></span>同一个浏览器不同的标签页发起同一个请求,sessionId相同吗?</li> </ol> <blockquote> <div class="blockquote-item"> 是相同的,因为依旧遵照这同一个浏览器同一个请求,其sessionId是不变的。 </div> </blockquote> <ol> <li data-list="ordered"><span class="ql-ui"></span>不同浏览器发起同一个请求,sessionId相同吗?</li> </ol> <blockquote> <div class="blockquote-item"> 是不同的,因为请求的对象都变了,sessionId肯定不同 </div> </blockquote> <p>口说无凭,我进行了实验,写了一个很简单的请求,进行了测试。</p> <div class="ql-code-block-container"> <div class="ql-code-block"> <span class="ql-token hljs-meta">@GetMapping("/test")</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">public</span> <span class="ql-token hljs-keyword">void</span> <span class="ql-token hljs-title">test(HttpServletRequest request, HttpServletResponse response)</span> <span class="ql-token hljs-keyword">throws</span> IOException { </div> <div class="ql-code-block"> <span class="ql-token hljs-type">String</span> <span class="ql-token hljs-variable">id</span> <span class="ql-token hljs-operator">=</span> request.getSession().getId(); </div> <div class="ql-code-block"> response.getWriter().write(id); </div> <div class="ql-code-block"> } </div> </div> <p>Edge浏览器的SessionId:</p> <p><span class="ql-font-monospace"> </span><img src="https://pic.code-nav.cn/planet_post_image/1620599227736473602/70hahm93.jpeg"></p> <p><img src="https://pic.code-nav.cn/planet_post_image/1620599227736473602/6nbd05zi.jpeg"></p> <p>Chrome的SessionId</p> <p><img src="https://pic.code-nav.cn/planet_post_image/1620599227736473602/rzfvz08a.jpeg"></p> <p><span class="ql-font-monospace"> </span></p> <p>总结:总结:不管是否是同一个用户还是不同的标签,只要符合<strong>同一个浏览器同一个请求</strong>,那么的sessionId一定是相同的!</p> <p><br></p> <h2><strong style="color: rgb(51, 51, 51);">参考</strong></h2> <p><br></p> <p><a href="https://blog.csdn.net/java_faep/article/details/78082802" target="_blank" style="color: rgb(65, 131, 196);">服务器端Session、客户端Session和Cookie的区别_session在网络应用中称为会话,每个用户首次与web服务器建立连接时,就会产生一个se-CSDN博客</a></p> <p><a href="https://blog.csdn.net/samniwu/article/details/90417160" target="_blank" style="color: rgb(65, 131, 196);">java中session的用法与原理-CSDN博客</a></p> <p><a href="https://blog.csdn.net/qq_41538097/article/details/106239901" target="_blank" style="color: rgb(65, 131, 196);">session何时被创建,何时被销毁以及设置session过期时间_session对象在什么时候被创建-CSDN博客</a></p> <p><a href="https://blog.csdn.net/hanziang1996/article/details/78969044" target="_blank" style="color: rgb(65, 131, 196);">Session的生命周期和工作原理-CSDN博客</a></p> <p><a href="https://blog.csdn.net/zhujason9107/article/details/52808648" target="_blank">session什么情况下会改变_什么样的情况下会出现不同session-CSDN博客</a></p> <p><br></p> <p><br></p> </div> </body> </html>
