← 返回题目列表

Cookie 和 Session 有什么区别?分布式环境如何管理 Session?

高频 中等 第 4 / 23 题 更新于 2026/07/25
CookieSessionHttpSession分布式会话

简化版

Cookie 存在客户端(浏览器),随每次请求自动带给服务器;Session 存在服务端,客户端只保存一个 session id(通常放在名为 JSESSIONID 的 Cookie 里),服务器凭这个 id 找到对应的会话数据。所以 Cookie 数据用户可见可改(不能信任)、Session 数据在服务端安全。分布式环境下的问题:Session 存在单台机器内存,用户下次请求可能落到另一台机器上,查不到 Session(掉登录)。解决方案:粘性会话、Session 复制、集中式存储(Redis,最常用)、或改用 Token(如 JWT)

详细版

Cookie vs Session 对比:

维度CookieSession
存储位置客户端(浏览器)服务端
安全性用户可见可改,不能存敏感数据数据在服务端,相对安全
客户端保存完整数据只保存 session id
容量小(约 4KB)受服务端存储限制
生命周期由 Max-Age/Expires 控制由服务端过期时间控制
依赖依赖客户端支持依赖 session id 传递(通常靠 Cookie)

Session 的工作原理:

① 首次请求,服务端创建 Session → 生成 session id
② 通过 Set-Cookie: JSESSIONID=xxx 返回给浏览器
③ 浏览器后续请求自动带上 Cookie: JSESSIONID=xxx
④ 服务端用 id 找到对应的会话数据

分布式 Session 的四种方案:

方案原理优点缺点
粘性会话负载均衡把同一用户固定到同一台机器简单该机器挂了会话就丢
Session 复制各机器间同步 Session无单点同步开销大、扩展性差
集中式存储(Redis)Session 存 Redis,各机器共享主流、可扩展依赖 Redis 可用性
Token(JWT)状态放客户端 Token,服务端无状态天然分布式难主动失效、有其他权衡

完整版教学

一、位置决定信任边界

Cookie 和 Session 最本质的区别是数据存在哪,这决定了能不能信任

  • Cookie 在客户端:数据存在用户的浏览器里,用户能看到、能修改、能伪造。所以服务端绝不能盲信 Cookie 里的业务数据——比如把 isAdmin=true 存 Cookie,用户改一下就成管理员了。Cookie 适合存不敏感、或经过签名/加密保护的数据,以及 session id。
  • Session 在服务端:真正的会话数据(登录态、用户信息、购物车)存在服务器,客户端只拿到一个标识符(session id)。用户无法直接篡改服务端数据。但 session id 一旦被窃取,攻击者就能冒用这个会话——所以 session id 的安全至关重要。

二、Cookie 的关键安全属性

Cookie 有几个安全属性是面试高频追问点:

属性控制点面试里要说清的效果
HttpOnly浏览器脚本能否读取不能阻止 Cookie 随请求发送,但能降低 XSS 直接偷取 session id 的风险
Secure传输通道只在 HTTPS 请求中携带,避免明文链路泄露
SameSite=Lax/Strict跨站请求携带策略能降低 CSRF 利用登录态发起危险请求的概率
Max-Age/Expires生命周期控制浏览器端 Cookie 何时过期,和服务端 Session 过期不是同一个概念
  • HttpOnly:设置后,JavaScript 无法读取这个 Cookie(document.cookie 读不到),能有效降低 XSS 窃取 session id 的风险。session id 的 Cookie 一定要加 HttpOnly。
  • Secure:设置后,Cookie 只在 HTTPS 加密连接中传输,防止明文传输被窃听。
  • SameSite:控制跨站请求是否携带 Cookie(Strict/Lax/None),能缓解 CSRF 攻击(跨站请求不带 Cookie,攻击者就无法利用你的登录态)。
  • Domain / Path:决定 Cookie 发送给哪些域名和路径。
  • Max-Age / Expires:决定 Cookie 的生命周期(不设则为会话 Cookie,关浏览器就没了)。

安全的 session Cookie 配置:HttpOnly + Secure + SameSite

Set-Cookie: JSESSIONID=9f3c...; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=1800

记忆钩子:Cookie 属性保护的是“浏览器如何保存和发送 id”,Session 安全保护的是“服务端如何识别和管理会话”,两层不能互相替代。

三、Session 的工作方式与优缺点

Session 的完整流程:

  1. 用户首次请求,服务端调用 request.getSession() 创建一个 Session,分配一个唯一的 session id
  2. 服务端通过响应头 Set-Cookie: JSESSIONID=xxx 把 session id 返回给浏览器。
  3. 浏览器后续请求自动带上 Cookie: JSESSIONID=xxx
  4. 服务端根据 id 在自己的存储里找到对应的会话数据

Session 的优点:服务端完全掌控——可以随时主动使某个会话失效(踢人下线)、方便存储较大的状态。缺点要占用服务端存储资源,且默认存在单机内存里,分布式下会出问题(下一节)。

四、分布式下的核心问题:状态绑定在单机内存

传统 Session 默认存在单台 Tomcat 的内存里。当系统部署多台机器 + 负载均衡时,问题来了:

用户在机器 A 上登录,Session 存在 A 的内存里。他下一次请求被负载均衡分发到机器 B,而 B 的内存里没有这个 Session——服务端查不到会话数据,表现为登录态丢失、购物车清空、验证码失效

根因是:状态(Session)绑定在了单个实例的内存里,而请求可能落到任何一台机器。要解决,就得让多台机器能共享或都能访问到 Session

五、四种分布式 Session 方案的权衡

① 粘性会话(Sticky Session):负载均衡根据 session id(或 IP)把同一用户的请求固定分发到同一台机器。这样用户始终访问存着他 Session 的那台。优点:简单,不用改应用。缺点那台机器一旦宕机/重启,落在它上面的用户 Session 全丢(掉登录);且负载可能不均。

② Session 复制(Replication):让集群里各台机器互相同步 Session,每台都有全量 Session。优点:无单点,任意机器都能处理。缺点同步开销大(每次 Session 变更要广播到所有机器),机器越多同步成本越高,扩展性差,不适合大集群。

③ 集中式存储 / Redis(最主流):把 Session 统一存到外部的 Redis(或其他共享存储),所有机器都从 Redis 读写 Session。优点:各机器共享同一份、可水平扩展、机器增减不影响 Session。缺点依赖 Redis 的可用性(Redis 挂了会话受影响,需 Redis 高可用)、要考虑序列化兼容。Spring Session 就是这个方案的标准实现(@EnableRedisHttpSession 一行接入)。这是分布式 Session 的默认选择。

④ Token(如 JWT):不用服务端 Session,把用户状态编码进一个 Token 放在客户端,服务端无状态——每次请求带 Token,服务端验签就知道用户是谁。优点:天然分布式(服务端不存状态,随便哪台机器都能验证)。缺点难以主动失效(Token 签发后到期前一直有效,登出/封禁难处理,需黑名单等补救)、Token 较大、不能存敏感信息。

举个数字例子:假设有 3 台 Tomcat,每台内存里有 2 万个 Session。使用复制方案时,一次购物车更新可能要同步给另外 2 台;如果扩大到 20 台,同一次变更要同步给另外 19 台,网络和序列化成本会明显放大。改用 Redis 集中式 Session 后,每次请求只按 sessionId -> Redis key 读写一次共享存储,应用实例增减不会改变同步扇出。

六、安全风险与选型建议

安全要点

  • session id 要足够随机(防猜测),登录后应重新生成 session id(防会话固定攻击——攻击者预设一个 id 诱导你用它登录)。
  • session Cookie 走 HTTPS + HttpOnly + SameSite
  • 登出时要清理服务端 Session(或撤销 Token),不能只删客户端 Cookie。

选型建议

  • 传统 Web 应用、需要强撤销能力(随时踢人下线)Redis 集中式 Session 很自然、稳定可控。
  • 跨端 API、微服务、多客户端 → 可考虑 Token(JWT),服务端无状态更省心。
  • 不要为了「分布式」就盲目上 JWT——很多系统用 Redis Session 已经足够,且撤销、安全性更好控制。JWT 的「无状态」也带来「难失效」的代价,要权衡。

七、常见误区与追问

  • 误区:Cookie 设置了 HttpOnly 就不会被攻击。 HttpOnly 只是防止脚本直接读取 Cookie,不能阻止浏览器自动携带 Cookie,也不能替代 XSS 修复和 CSRF 防护。
  • 误区:Session 一定比 Cookie 安全,所以可以随便用。 Session 数据在服务端更可控,但 session id 泄露后仍会被冒用,还要配合 HTTPS、重新生成 id、过期和登出清理。
  • 追问:Redis Session 和 JWT 最大取舍是什么? Redis Session 有服务端状态,容易主动失效和统一管理;JWT 无状态更适合跨服务验证,但撤销和体积控制更麻烦。
  • 追问:为什么分布式环境下粘性会话不算根治? 它只是让请求尽量落回原机器,机器宕机、重启或扩缩容时会话仍会丢,也会造成负载不均。
  • 误区:把用户角色放到 Cookie 里就能减少服务端查询。 未签名的 Cookie 可被篡改;即使签名,也要考虑权限变更后的实时性,关键权限仍应以后端可信数据为准。
  • 追问:登录成功后为什么要重新生成 session id? 这是为了防会话固定攻击,避免攻击者提前准备一个 id,让用户登录后继续使用这个被攻击者知道的会话标识。

八、加强记忆

Cookie 在客户端(用户可见可改、不能存敏感数据、随请求自动带)、Session 在服务端(存真实会话数据、客户端只存 session id / JSESSIONID)。Session 流程:服务端创建 Session 生成 id → Set-Cookie 返回 → 浏览器后续自动带 → 服务端凭 id 找会话。Cookie 安全属性:HttpOnly(防 JS 读、防 XSS 窃 id)、Secure(仅 HTTPS)、SameSite(防 CSRF)分布式 Session 问题:Session 在单机内存,请求落到别的机器就查不到(掉登录)。四方案:粘性会话(简单但宕机丢会话)、Session 复制(无单点但扩展差)、Redis 集中式(主流、可扩展、依赖 Redis)、Token/JWT(无状态天然分布式,但难主动失效)。安全:登录后重新生成 session id 防会话固定。选型:要强撤销用 Redis Session、跨端 API 用 Token,别盲目上 JWT