| 維度 | Cookie | Session |
|---|---|---|
| 存儲位置 | 客戶端(瀏覽器) | 伺服器端(檔案/資料庫/Redis等) |
| 容量限制 | 單個 ~4KB,域名總計 ~20-50 個 | 受限於伺服器儲存空間 |
| 生命週期 | 可設定過期時間,持久化 | 預設瀏覽器關閉失效,可配置 gc_maxlifetime |
| 安全性 | 客戶端可竄改、攔截、XSS 竊取 | 敏感資料不離開伺服器,相對安全 |
| 跨域支援 | 受同源策略限制,可設定 domain/path | 需共享 Session ID(Cookie/URL 重寫) |
| HTTP 交互 | 每請求自動攜帶 | 僅傳遞 Session ID |
# 伺服器發送 Cookie(Response Header)
Set-Cookie: PHPSESSID=abc123; path=/; HttpOnly; Secure; SameSite=Lax
Set-Cookie: user_pref=dark_mode; expires=Wed, 31 Dec 2025 23:59:59 GMT; path=/
# 瀏覽器自動攜帶(Request Header)
Cookie: PHPSESSID=abc123; user_pref=dark_mode
HttpOnly:禁止 JavaScript 讀取(document.cookie),防 XSS 竊取 Session IDSecure:僅 HTTPS 傳輸SameSite:Strict/Lax/None,防 CSRFDomain/Path:作用範圍控制session_start()$_COOKIE[session_name()](預設 PHPSESSID)sess_ 檔案,反序列化填入 $_SESSIONSet-Cookie$_SESSION 寫回儲存介質session.save_handler = files); php.ini 關鍵配置
session.save_handler = files
session.save_path = "/var/lib/php/sessions" ; 或 "N;/path" 分級目錄
session.gc_probability = 1
session.gc_divisor = 1000 ; GC 機率 1/1000
session.gc_maxlifetime = 1440 ; 24 分鐘過期
session.name = PHPSESSID ; Cookie 名稱
session.cookie_lifetime = 0 ; 0 = 瀏覽器關閉失效
session.cookie_path = /
session.cookie_httponly = 1
session.cookie_secure = 1 ; 僅 HTTPS
session.use_strict_mode = 1 ; 拒絕未初始化的 Session ID
session_start() 有 gc_probability/gc_divisor 機率觸發save_path 所有 sess_* 檔案,檢查 filemtime + gc_maxlifetime < time()unlink() 刪除gc_probability = 0,改用 cron 定時腳本清理,避免請求阻塞session.save_handler = user)實作 SessionHandlerInterface 或註冊六個回調:
<?php
class MySessionHandler implements SessionHandlerInterface {
private $db;
public function __construct(PDO $db) { $this->db = $db; }
public function open($savePath, $sessionName) { return true; }
public function close() { return true; }
public function read($id) {
$stmt = $this->db->prepare("SELECT data FROM sessions WHERE id = ? AND expiry > ?");
$stmt->execute([$id, time()]);
return $stmt->fetchColumn() ?: '';
}
public function write($id, $data) {
$expiry = time() + ini_get('session.gc_maxlifetime');
$stmt = $this->db->prepare("REPLACE INTO sessions (id, data, expiry) VALUES (?, ?, ?)");
return $stmt->execute([$id, $data, $expiry]);
}
public function destroy($id) {
$stmt = $this->db->prepare("DELETE FROM sessions WHERE id = ?");
return $stmt->execute([$id]);
}
public function gc($maxlifetime) {
$stmt = $this->db->prepare("DELETE FROM sessions WHERE expiry < ?");
return $stmt->execute([time()]);
}
}
$handler = new MySessionHandler($pdo);
session_set_save_handler($handler, true); // true = 註冊關閉函數
session_start();
?>
PHPSESSID=abc,最透明/page.php?PHPSESSID=abc 或 /page.php;PHPSESSID=abc(session.use_trans_sid=1)<input type="hidden" name="PHPSESSID" value="abc">(舊技術,少用)誤區:「關閉瀏覽器 Session 就消失了」
真相:Session 檔案仍保留在伺服器,直到 GC 清理。關閉瀏覽器僅刪除會話 Cookie(cookie_lifetime=0),下次訪問無 ID 自然無法關聯舊 Session。若 Cookie 設定cookie_lifetime > 0持久化,或手動傳回舊 ID,Session 依然有效。
session.use_strict_mode = 1 防 Session Fixationsession.cookie_httponly = 1 防 XSS 竊取 IDsession.cookie_secure = 1 僅 HTTPS 傳輸session.cookie_samesite = 'Lax' 防 CSRFsession_regenerate_id(true) 重新生成 ID、銷毀舊 Sessionsession_destroy() + setcookie(session_name(), '', time()-3600, '/') 徹底清理JSESSIONID,PHP 使用 PHPSESSID,本質相同Cookie 是客戶端狀態持久化機制,Session 是伺服器端狀態管理機制,Session 通常借助 Cookie 傳遞 ID。理解 HTTP 無狀態本質、Cookie/Session 交互流程、PHP Session 存儲與 GC 機制、安全屬性配置,是構建安全、可擴展 Web 應用的基礎。現代架構建議:Session 資料極小化(僅存用戶 ID、權限標識),業務資料放 Redis/資料庫,Session 存儲統一用 Redis Cluster 實現分布式共享。