Web 中的 Session 到底是什么?

博客参考:https://blog.by24.cn/archives/about-session.html#comment-10457
推荐阅读:http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/

在 Web 开发中,会使用一些技术来维持用户登录状态。此时,你会立刻想到 Session,但如果要你解释为什么能维持登录状态,你也只能说:大概是 SessionId 之类的,巴拉巴拉。

是的,之前别人这么问我,我估计也是扯这些东西。你要问为什么是这些东西,那我只能跟你说八股上是这样写的。

大部分人从八股中了解 Session 知识,但这些还不足以让你对它有清晰的认知。

不信我问你几个问题,SessionId 是什么?SessionData 是什么?面试官常问的 Session 和 Cookie 的关系?Sever-Side Session 和 Client-Side Session 是什么?Java 常用的 Web 容器 Tomcat 是如何处理 Session 的?

如果你无法清楚的解释上面的问题,那么这篇文章非常适合你。

登录状态与 Session

Session 翻译成「会话」,他表示的是一次「谈话」,谈话期间双方可以任意通信。

在 Web 开发领域,Session 做的就是维持用户登录状态。那么它是怎么做的呢?

回想一下登录的场景,输入账号密码登录后,Cookie 中会多一个 SessionId 信息,该 SessionId 是你的身份证,后续的请求 Cookie 都会包含该 SessionId,这样服务就知道你是「你」。

那么问题来了,服务端是如何根据你的 SessionId 来判断你是「你」的?

当然是登录的时候,把你的信息给「存」了起来,用 SessionId 把你的信息关联起来。流程如图:

image-20230704154258027

用户渣渣丰登录时,服务查找 “zzf” 用户信息,将用户信息存到 Session存储中心,然后返回 SessionId。渣渣丰后续的请求都不用再登录了,带上 SessionId=10010,服务器去 Session 存储中心查 id 为 10010 的数据,便能直接获取用户信息。若找不到,则表示用户未登录,走登录流程即可。

返回给客户端的 id 称作 SessionId,SessionId 关联的数据就是 SessionData。Session 这个模糊的概念就可以简单的理解为:SessionId + SessionData

两种 Session 存储策略

Server-Side Session

上面的登录过程中,SessionData 是存储在服务端的,称作 Server-Side Session,,这也是大多数网站使用的存储策略。他的特点是客户端传输只需要传 SessionId,在没有理解 Session 前,就很容易把 SessionId 当成 Session 本身,而无视了 SessionData 的存在,这正是很多人理解不了 Session 的原因。

对于还未登录的新用户,去访问系统的其他请求,此时用户并未携带 SessionId。服务器会处理当前请求,新增一条 Session 数据,其中 SessionData 为空,然后返回 SessionId,并提示用户登录。

Client-Side Session

Server-Side Session 相反,Client-Side Session SessionData 是在客户端(浏览器)存储的。每次向服务器发起请求,都要带上 SessionData 信息。

因此,这种情况都压根不存在 SessionId 这个概念,很多人也很容易因此搞混,不清楚 Session 究竟存在哪里。

对于新用户来说,本地没有任何信息,服务器便会初始化一个空的 SessionData 返回。后续的通信中,SessionData 才会被填充有意义的数据。

这种做法,很明显有个巨大漏洞:用户直接修改本地的 SessionData 数据,冒充管理员怎么办?

因此,使用 Client-Side Session 需要使用加密或者签名等机制,来保证数据安全,确保 SessionData 数据都是由服务端生成的。

严格来说,Session 和 Cookie 其实没有半毛钱关系,只是 Cookie 常用做 Session 的载体,因此很多人也被弄得迷迷糊糊。

还记得上面客户端「带」信息(SessionId / SessionData)的过程吗,信息传给服务端需要一个载体,这个载体可以是任何服务器能接收的东西,例如放在 URL 中,我们也完全可以把 Session 信息放到 Header 中,事实上也有很多网站是这么做的,比如一些禁止使用 Cookie 的网站。

大多数人选择使用 Cookie,自然是有他优势所在。服务端可以设置 Cookie 中的信息,且禁止客户端修改,这样能防止 Cookie 信息被篡改。由于 Cookie 中的信息在通信中,双方都能接收,因此 Cookie 是很适合存 Session 信息。

总之,Cookie 只是一个用户存储和传输 Session 信息的工具,仅此而已。

Web 容器对 Session 的支持

在 Java 开发中,经常使用到 Tomcat 容器,他提供了对 Session 的支持。 Tomcat 也是属于 Server-Side Session,查看 Cookie 可以发现他使用 JESSIONID 字段存储 SessionId,SessionData 则存储在服务端的内存中。

Tomcat 默认使用 StandardManager 来管理 SessionData,查看源代码可以发现,Tomcat 容器在退出时将 Session 数据持久化到磁盘中,启动时从磁盘中加载 Session。

对于 Tomcat 来说,他的「Session 存储中心」就是内存,但 Session 也支持其他方式的存储,例如 MySQL、Redis,甚至可以直接存成文本文件。Spring Session 就对 Session 做了全方位的支持,使得 Session 更易用。

Session 和 JWT

Session 和 JWT 本身就并非对立面,甚至是「一家」的。JWT 是一种生成 Token 的方式,他通过签名保证 Token 信息不被篡改。

使用 JWT 的时候,也是登录时候拿到一个 token,后续所有请求都带上 token。你可能会说,哎这不是 Server-Side Session 的方式吗?

并非如此,服务端并没有保存任何信息。相反用户的信息 (token) 是被客户端持有的,只不过该信息并非明文,需要服务端解密才能查看。

因此,JWT 实际上就是 Client-Side Session,比直接传输 SessionData,他将传输内容变得更安全精简,只需一串字符即可。服务端只需要按照既定的规则验证签名,解析用户信息即可,也不用额外存储任何信息。

总而言之,Session 更像是一套用于维持客户端和服务端通信的方案,而 JWT 则是具体实现。


Web 中的 Session 到底是什么?
http://wszzf.top/2023/07/04/Web 中的 Session/
作者
Greek
发布于
2023年7月4日
许可协议