深入理解 Cookie 与 Session —— Web 状态保持详解与实战

HTTP 协议是**无状态(Stateless)**的,这意味着:

  • 每次请求之间,服务器不会主动记住你是谁。

  • 用户在一次请求中登录了,下一次请求服务器依然当你是新访客。

  • 像购物车、个人中心、支付流程等功能无法在多次请求之间共享状态。

所以,状态保持技术的核心目标是:

让服务器在多个 HTTP 请求中"记住"客户端的身份和相关信息。

最常见的两种技术就是 CookieSession


二、Cookie ------ 浏览器端的状态记录

1. 概念

Cookie 是一小段存储在浏览器端 的文本数据,由服务器生成并通过响应头 Set-Cookie 发送给浏览器保存。之后浏览器访问同一域名时会自动携带 Cookie 发送给服务器。

2. 工作原理

  1. 首次请求:浏览器访问服务器,服务器在响应头中设置 Cookie。

  2. 存储:浏览器将 Cookie 保存到本地文件(每个浏览器保存方式不同)。

  3. 后续请求:浏览器在请求头中自动带上 Cookie 信息。

  4. 服务器读取:服务器解析 Cookie,从而识别用户身份。

流程图示意:

css 复制代码
[浏览器] --请求--> [服务器] 
[服务器] --Set-Cookie--> [浏览器保存] 
[浏览器] --携带Cookie请求--> [服务器读取并识别]

3. 示例

html 复制代码
HTTP/1.1 200 OK
Set-Cookie: username=zhangsan; Path=/; HttpOnly; Max-Age=3600

下次请求:

html 复制代码
GET /index.html HTTP/1.1
Cookie: username=zhangsan
属性 作用
Name=Value 键值对数据
Domain 指定 Cookie 生效的域名
Path 指定 Cookie 生效的路径
Expires / Max-Age 设置过期时间
HttpOnly 防止 JavaScript 读取,增强安全性
Secure 仅在 HTTPS 下传输

优点:

  • 浏览器自动管理,无需额外代码处理传输。

  • 可以持久化存储(设置过期时间)。

缺点:

  • 存储容量小(单个约 4KB)。

  • 安全性差(数据明文存储在客户端,易被窃取或篡改)。

  • 每次请求都会携带 Cookie,会增加流量消耗。


三、Session ------ 服务器端的状态记录

1. 概念

Session 是一种服务器端存储 的会话数据机制。

当用户第一次访问时,服务器会为其创建一个 Session,并分配一个唯一的 Session ID,将这个 ID 返回给浏览器保存(通常通过 Cookie)。

2. 工作原理

  1. 首次访问:服务器生成 Session 数据(例如登录状态、购物车内容),并生成唯一的 Session ID。

  2. 返回 Session ID :服务器通过 Cookie 将 Session ID 发给浏览器(如 JSESSIONID=xyz123)。

  3. 浏览器保存:浏览器保存 Session ID 到 Cookie。

  4. 后续请求:浏览器在请求中携带 Session ID,服务器根据该 ID 找到对应的 Session 数据。

3. 示例

html 复制代码
Set-Cookie: JSESSIONID=xyz123; Path=/; HttpOnly

后续请求:

html 复制代码
GET /cart HTTP/1.1
Cookie: JSESSIONID=xyz123

4. Session 特性

  • 存储位置:服务器内存 / 数据库 / 分布式缓存(如 Redis)。

  • 生命周期:默认 30 分钟(可配置)。

  • 容量限制:取决于服务器内存,理论上可存储较大数据。

  • 安全性:数据不直接暴露给客户端,安全性高。


四、Cookie 与 Session 的关系

实际上,Session 通常依赖 Cookie 来保存 Session ID

  • Cookie 中只保存一个 Session ID

  • 具体的用户数据(登录状态、购物车等)存放在服务器的 Session 对象中。

这种方式结合了两者的优点:

  • 减少 Cookie 存储压力。

  • 提升安全性(敏感数据不放在客户端)。


五、Cookie 与 Session 的对比

对比项 Cookie Session
存储位置 客户端(浏览器) 服务器端
安全性 易被窃取或篡改(需加密) 高,数据不暴露给客户端
存储容量 单个 ≤ 4KB 受服务器内存限制
生命周期 可设置过期时间 默认短时存储,可配置
性能影响 占用客户端空间,增加网络流量 占用服务器内存
使用场景 保存非敏感、需要持久化的数据 保存敏感数据(如登录信息)

六、实际开发中的应用

1. 用户登录流程(Session 版)

  1. 用户输入账号密码并提交。

  2. 服务器验证成功后,创建 Session,保存用户信息。

  3. Session ID 写入 Cookie。

  4. 后续请求带上 Session ID,服务器即可识别用户。

2. 用户登录流程(Cookie 版)

  1. 用户输入账号密码并提交。

  2. 服务器验证成功后,将用户信息加密后写入 Cookie。

  3. 后续请求直接解析 Cookie 获取用户信息(需注意安全风险)。


七、安全性问题与防护措施

Cookie 和 Session 都是状态保持机制,但如果使用不当,可能被攻击者利用。常见问题包括:

原理 :攻击者获取了你的 Cookie(尤其是 Session ID),就能冒充你的身份。
场景 :公共 WiFi 抓包、XSS 注入读取 Cookie。
防护措施

  • 使用 HTTPS 传输,防止中间人截获。

  • 设置 HttpOnly,防止 JS 脚本读取 Cookie。

  • 设置 Secure,仅允许在 HTTPS 下传输。

原理 :攻击者在客户端或通过响应头写入相同名称的 Cookie,从而覆盖原有 Cookie 内容,导致身份被冒用或数据被篡改。
场景

  • 同一域名下的不同子域篡改 Cookie。

  • 恶意响应头设置同名 Cookie 覆盖原值。
    防护措施

  • 为 Cookie 设置明确的 DomainPath 限制作用范围。

  • 对 Cookie 值进行签名和验证,防止篡改。

3. Session 固定攻击(Session Fixation / Session 重定义)

原理 :攻击者提前获取或制造一个合法的 Session ID,然后诱导受害者使用该 Session ID。一旦受害者登录,攻击者就能使用相同的 Session ID 登录到受害者的账号。
流程示例

  1. 攻击者访问网站,获取一个合法的 Session ID=abc123

  2. 攻击者将该 Session ID 发送给受害者(通过 URL、恶意链接等方式)。

  3. 受害者在该 Session ID 下登录。

  4. 攻击者用相同的 Session ID 就能直接登录受害者账号。

防护措施

  • 登录成功后重新生成 Session ID(关键)。

  • 不允许通过 URL 传递 Session ID。

  • 对 Session 设置较短的过期时间,并限制 IP/UA 绑定。

4. Session 过期处理不当

原理 :Session 过期后,如果前端没有提示重新登录,可能导致用户操作失败,体验差。
防护措施

  • 后端返回特定状态码(如 401/440)。

  • 前端检测到状态码后跳转到登录页,并可选保存用户输入内容。


在 Java Web(Servlet)开发中,Cookie 和 Session 是内置支持的,我们可以很方便地使用它们。

java 复制代码
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;

public class SetCookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 创建 Cookie 对象
        Cookie cookie = new Cookie("username", "zhangsan");
        // 设置 Cookie 过期时间(秒),这里设置 1 小时
        cookie.setMaxAge(60 * 60);
        // 设置作用路径(默认是当前项目路径)
        cookie.setPath("/");
        // 添加到响应
        response.addCookie(cookie);
        response.getWriter().write("Cookie 已设置!");
    }
}
java 复制代码
public class GetCookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie c : cookies) {
                if ("username".equals(c.getName())) {
                    response.getWriter().write("读取到 Cookie:username=" + c.getValue());
                }
            }
        } else {
            response.getWriter().write("没有找到 Cookie");
        }
    }
}

2. Session 的使用

2.1 创建与存储 Session 数据
java 复制代码
public class SetSessionServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 获取 Session,没有则创建
        HttpSession session = request.getSession();
        // 存储数据到 Session
        session.setAttribute("user", "zhangsan");
        // 设置 Session 过期时间(秒)
        session.setMaxInactiveInterval(30 * 60);
        response.getWriter().write("Session 已存储!");
    }
}
2.2 获取 Session 数据
java 复制代码
public class GetSessionServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        HttpSession session = request.getSession(false); // false 表示没有就不创建
        if (session != null) {
            String user = (String) session.getAttribute("user");
            if (user != null) {
                response.getWriter().write("Session 中的 user = " + user);
            } else {
                response.getWriter().write("Session 中没有 user 数据");
            }
        } else {
            response.getWriter().write("Session 不存在");
        }
    }
}

3. 小技巧与注意事项

  • Session 默认使用 Cookie 存 Session ID(JSESSIONID),如果禁用 Cookie,可以通过 URL 重写:
java 复制代码
response.encodeURL("myServlet");
  • Session 清除
java 复制代码
session.invalidate();
  • Cookie 安全性:对于敏感信息,应加密后再存储,或者仅存 Session ID。

  • Session 分布式存储:在分布式环境中使用 Redis 等中间件来存储 Session,实现会话共享。


九、总结

  1. Cookie 适合存放少量非敏感数据,可跨会话持久化。

  2. Session 安全性高,适合保存登录等敏感信息。

  3. 最佳实践:用 Cookie 存 Session ID,核心数据放 Session。

  4. Java Web 开发 内置了 Cookie 和 Session API,用法简单高效。

  5. 在安全上,需防范 Cookie 重定义Session 固定攻击Cookie 劫持 等问题。

相关推荐
烛阴几秒前
Clamp
前端·webgl
Warren981 小时前
公司项目用户密码加密方案推荐(兼顾安全、可靠与通用性)
java·开发语言·前端·javascript·vue.js·python·安全
专注VB编程开发20年2 小时前
c#,vb.net全局多线程锁,可以在任意模块或类中使用,但尽量用多个锁提高效率
java·前端·数据库·c#·.net
JarvanMo2 小时前
Google Connect 8月14日纪实
前端
猩猩程序员3 小时前
Go 1.24 全面拥抱 Swiss Table:让内置 map 提速 60% 的秘密
前端
1024小神3 小时前
vue3 + vite项目,如果在build的时候对代码加密混淆
前端·javascript
轻语呢喃3 小时前
useRef :掌握 DOM 访问与持久化状态的利器
前端·javascript·react.js
wwy_frontend4 小时前
useState 的 9个常见坑与最佳实践
前端·react.js
w_y_fan4 小时前
flutter_riverpod: ^2.6.1 应用笔记 (一)
前端·flutter