核心機制對比
| 特性 | Session | Cookie |
| 存儲位置 | 服務端(文件/Redis/DB) | 客戶端瀏覽器 |
| 生命週期 | 瀏覽器關閉失效(可配置) | 可設置具體過期時間 |
| 安全性 | 高(數據不暴露) | 低(可被竄改/竊取) |
| 容量限制 | 受服務端內存/磁盤限制 | 單個 4KB,域名下約 20-50 個 |
| 傳輸開銷 | 僅傳 Session ID(極小) | 每請求攜帶全部數據 |
Session 關鍵操作
<?php
// 必須在任何輸出前調用
session_start();
// 設置生命週期(服務端 GC 時間,單位秒)
ini_set('session.gc_maxlifetime', 86400); // 1 天
// 客戶端 Cookie 同步過期
session_set_cookie_params(86400, '/', '', true, true); // HTTPS+HttpOnly
// 寫入
$_SESSION['user'] = ['id' => 1001, 'name' => '張三'];
// 讀取
$user = $_SESSION['user'] ?? null;
// 刪除單項
unset($_SESSION['user']);
// 銷毀整個 Session(含文件)
session_destroy(); // 需配合 $_SESSION = [] 釋放內存變量
Cookie 關鍵操作
<?php
// 設置:名、值、過期時間戳、路徑、域、Secure、HttpOnly
setcookie('remember_token', 'a1b2c3d4', [
'expires' => time() + 2592000, // 30 天
'path' => '/',
'domain' => '', // 當前域
'secure' => true, // 僅 HTTPS
'httponly' => true, // 防 XSS
'samesite' => 'Lax' // CSRF 防護
]);
// 讀取
$token = $_COOKIE['remember_token'] ?? '';
// 刪除(設置過去時間)
setcookie('remember_token', '', ['expires' => time() - 3600, 'path' => '/']);
// 存儲陣列/對象:序列化 + Base64
$cookieData = base64_encode(serialize(['uid' => 1001, 'exp' => time() + 86400]));
setcookie('user_data', $cookieData, ['expires' => time() + 86400, 'path' => '/']);
// 讀取還原
$data = unserialize(base64_decode($_COOKIE['user_data'] ?? ''));
自動登錄完整流程
- 登錄頁:驗證賬號密碼 → 生成隨機 Token → 寫入 DB(user_id, token, expires_at, user_agent, ip) → 設置 Cookie
remember_token → 寫入 Session → 跳轉首頁。
- 訪問受保護頁:
function checkAuth(): ?array {
// 1. Session 有效直接返回
if (!empty($_SESSION['user'])) return $_SESSION['user'];
// 2. 無 Session,檢查 Cookie Token
$token = $_COOKIE['remember_token'] ?? '';
if (!$token) return null;
// 3. 驗證 Token(防時序攻擊用 hash_equals)
$record = DB::query("SELECT * FROM remember_tokens WHERE token = ? AND expires_at > NOW()", $token);
if (!$record || !hash_equals($record['user_agent'], $_SERVER['HTTP_USER_AGENT'] ?? '')) {
// Token 無效/劫持,清理 Cookie
setcookie('remember_token', '', ['expires' => time() - 3600, 'path' => '/']);
return null;
}
// 4. 刷新 Token 安全性(可選:輪換 Token)
// 5. 寫入 Session,返回用戶信息
$user = getUserById($record['user_id']);
$_SESSION['user'] = $user;
return $user;
}
- 退出登錄:
function logout(): void {
$token = $_COOKIE['remember_token'] ?? '';
if ($token) {
DB::execute("DELETE FROM remember_tokens WHERE token = ?", $token);
setcookie('remember_token', '', ['expires' => time() - 3600, 'path' => '/']);
}
$_SESSION = [];
session_destroy();
}
安全加固清單
- ✅ 全站 HTTPS,Cookie 設置
Secure、HttpOnly、SameSite=Lax/Strict。
- ✅ Token 使用
random_bytes(32) 生成,存儲 hash('sha256', $token) 到 DB,防止 DB 洩露導致 Token 被盜用。
- ✅ 綁定 User-Agent、IP 段(可選),異常時強制失效。
- ✅ 限制單用戶同時有效 Token 數量(如最多 5 個設備)。
- ✅ 定期清理過期 Token 記錄。
- ✅ Session 存儲建議遷移至 Redis,支援集群、TTL 自動過期。