首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Cookie 與 Session 區別與聯繫詳解:原理、存儲、安全性與分布式擴展

     編輯:Java 綜合教學

Cookie 與 Session 區別與聯繫詳解:原理、存儲、安全性與分布式擴展

Cookie 和 Session 是 Web 會話管理的雙基石。本文從 HTTP 無狀態本質切入,系統對比兩者機制、存儲位置、生命周期、安全性、跨域行為,並給出分布式 Session 共享方案。

一、HTTP 無狀態與會話管理需求

HTTP 協議本質是無狀態的:每個請求獨立,服務端不記住客戶端身份。為了識別用戶狀態(登錄態、購物車、偏好設置),引入了會話管理機制:

  • Cookie:客戶端存儲,隨請求自動發送
  • Session:服務端存儲,通過 SessionID 關聯

二、核心差異對比表

維度CookieSession
存儲位置瀏覽器端 (文件/內存)服務端內存/Redis/數據庫
存儲容量單個 ≤ 4KB,域名下 ≤ 20-50 個理論無上限 (受限服務端內存)
生命周期可設置過期時間 (持久/會話級)默認 30 分鐘無操作過期,可配置
安全性低:可被竊取、篡改、XSS 獲取高:數據不離開服務端,僅傳 ID
帶寬影響每請求攜帶,增加流量僅傳 SessionID (極小)
跨域支持受同源策略限制,可配置 Domain/Path需共享存儲或 Token 方案
禁用應對用戶可禁用 Cookie → 失效可用 URL 重寫 (jsessionid=xxx) 兼容
典型用途記住我、偏好設置、追蹤、CSRF Token用戶身份、權限、購物車、敏感業務數據

三、工作原理深度解析

1. Cookie 機制

// 服務端設置 Cookie (Servlet)
Cookie cookie = new Cookie("userId", "12345");
cookie.setMaxAge(60 * 60 * 24 * 7); // 7天過期,秒為單位;-1=會話級;0=刪除
cookie.setPath("/");                // 生效路徑
cookie.setDomain(".example.com");   // 跨子域共享
cookie.setHttpOnly(true);           // 防 XSS:JS 無法讀取
cookie.setSecure(true);             // 僅 HTTPS 傳輸
response.addCookie(cookie);

// 瀏覽器自動攜帶
// Request Headers: Cookie: userId=12345; JSESSIONID=ABC...

2. Session 機制

// 服務端創建/獲取 Session
HttpSession session = request.getSession(); // 無則創建,有則返回
HttpSession session = request.getSession(false); // 無則返回 null

// 存取數據
session.setAttribute("user", userObj);
User user = (User) session.getAttribute("user");

// 設置超時 (秒)
session.setMaxInactiveInterval(30 * 60); // 30分鐘

// 銷毀
session.invalidate();

// 底層流程:
// 1. 首次請求 → 服務端生成 SessionID (UUID) → 存入內存 Map
// 2. 通過 Set-Cookie: JSESSIONID=xxx 發送給瀏覽器
// 3. 後續請求 → 瀏覽器自動攜帶 Cookie: JSESSIONID=xxx
// 4. 服務端解析 Cookie → 從 Map 獲取 SessionData

四、SessionID 傳遞的三種方式

  1. Cookie (默認):JSESSIONID=abc 在 Cookie 中
  2. URL 重寫:/app/action;jsessionid=abc (Cookie 被禁用時備選)
  3. 隱藏表單字段:<input type="hidden" name="jsessionid" value="abc"> (極少用)

Servlet 容器自動處理,開發者無感知。response.encodeURL(url) 可自動追加 SessionID。

五、安全性最佳實踐

Cookie 安全屬性組合拳

Cookie cookie = new Cookie("token", "xxx");
cookie.setHttpOnly(true);   // 必須:防 XSS 竊取
cookie.setSecure(true);     // 必須:僅 HTTPS (生產環境)
cookie.setPath("/");        // 最小權限路徑
cookie.setDomain(".api.example.com"); // 最小權限域名
cookie.setMaxAge(3600);     // 短期過期
// SameSite 屬性 (Servlet 2.5+ 需手動設置 Header)
// response.addHeader("Set-Cookie", "token=xxx; SameSite=Strict; Secure; HttpOnly");

Session 安全加固

  • SessionID 足夠長、足夠隨機 (容器默認滿足)
  • 登錄後重新生成 SessionID:request.changeSessionId() 防 Session Fixation
  • 敏感操作二次驗證:修改密碼、轉賬需重新輸入密碼/OTP
  • 並發登錄控制:單用戶單 Session,新登錄踢舊

六、分布式 Session 共享方案

單體應用 Session 存內存,集群下請求分發到不同節點導致 Session 丟失。

方案原理優點缺點
Sticky Session (IP Hash)Nginx 將同一用戶固定路由到同一節點零代碼改動,性能最好節點故障 Session 丟失,擴容不均
Session Replication (Tomcat Cluster)節點間廣播同步 Session容器級透明網絡風暴,節點>5 不推薦
Redis 共享存儲 (主流)Session 序列化存 Redis,所有節點讀寫高可用、橫向擴展、數據持久化網絡開銷、序列化成本、單點風險(需哨兵/集群)
Database 共享存儲Session 存 MySQL/PostgreSQLACID、持久化性能差、不適合高併發
JWT / Token 無狀態用戶信息簽名存客戶端,服務端無狀態完全無狀態、極易擴展、跨域友好無法主動失效(需黑名單)、Token體積大、續簽邏輯複雜

Spring Session + Redis 實戰配置



    org.springframework.session
    spring-session-data-redis



spring:
  session:
    store-type: redis
    redis:
      namespace: spring:session
      flush-mode: on_save
  redis:
    host: localhost
    port: 6379

七、總結:如何選擇?

  • 少量非敏感、需持久化、跨會話 → Cookie (設置 HttpOnly+Secure+SameSite)
  • 用戶身份、權限、敏感業務、大數據 → Session (配合 Redis 共享)
  • 微服務、前後端分離、移動端、跨域 → JWT Token (Access Token + Refresh Token)
  • 極簡部署、單體、低併發 → 內存 Session + Sticky Session
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved