首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP Session 工作原理深度解析:從 HTTP 協議到源碼層面

     編輯:PHP 相關知識

核心問題:無狀態 HTTP 如何實現「有狀態」會話?

HTTP 協議本身是無狀態的,服務器無法識別兩個請求是否來自同一用戶。Session 通過 「服務器存儲數據 + 客戶端持有標識符」 的機制解決此問題。

完整交互流程 (抓包級解析)

第 1 次請求 (無 Cookie)


GET /test.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0...
Accept: */*

服務器響應 (建立 Session)


HTTP/1.1 200 OK
Date: Fri, 26 Aug 2025 07:44:22 GMT
Server: Apache/2.4.x PHP/8.2.x
X-Powered-By: PHP/8.2.x
Set-Cookie: PHPSESSID=abc123def456; path=/; HttpOnly; SameSite=Lax  ← 關鍵:下發 Session ID
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Content-Type: text/html; charset=utf-8

0  ← 輸出內容 (session 計數器初始值)

第 2 次請求 (攜帶 Cookie)


GET /test.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0...
Accept: */*
Cookie: PHPSESSID=abc123def456  ← 瀏覽器自動攜帶

服務器響應 (識別 Session)


HTTP/1.1 200 OK
...
Set-Cookie: PHPSESSID=abc123def456; path=/; HttpOnly; SameSite=Lax  ← 刷新過期時間
...
Content-Length: 1

1  ← 輸出內容 (計數器遞增)

PHP Session 核心配置 (php.ini 關鍵參數)

參數默認值說明生產建議
session.save_handlerfiles存儲引擎: files/redis/memcached/custom高併發改用 redis
session.save_path/tmp文件存儲路徑 (files 模式)專用目錄、權限 700
session.namePHPSESSIDCookie 名稱自定義如 APPSESSID
session.cookie_lifetime0Cookie 生命週期 (0=瀏覽器關閉失效)設定具體秒數如 3600
session.gc_maxlifetime1440服務端數據最大存活秒數 (GC 依據)與業務邏輯一致
session.gc_probability1GC 執行概率分子配合 divisor
session.gc_divisor1000GC 執行概率分母 (1/1000 請求觸發)高流量可調大
session.cookie_httponlyOn禁止 JS 讀取 Cookie (防 XSS)必須 On
session.cookie_secureOff僅 HTTPS 傳輸 CookieHTTPS 環境必須 On
session.cookie_samesiteLaxCSRF 防護: Strict/Lax/NoneLax 平衡體驗安全
session.use_strict_modeOff拒絕未初始化的 Session ID (防固定攻擊)建議 On

Session 存儲機制深度剖析

默認文件存儲 (save_handler=files)

  • 文件命名:sess_ (如 sess_abc123def456)
  • 數據格式:序列化字符串 key|s:len:"value";key2|i:123;
  • 性能瓶頸:大量小文件導致 inode 耗盡、目錄查找慢、NFS 鎖競爭。
  • 分層目錄優化:session.save_path = "2;/var/lib/php/sessions" (創建 2 級子目錄分散文件)。

Redis 存儲 (生產環境標配)


; php.ini 或運行時 ini_set
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=password&database=0&prefix=session:"
; 選項: weight=1, timeout=2.5, read_timeout=2, retry_interval=10

優勢:內存級速度、原子操作、集群化、TTL 自動過期、支援多實例負載均衡。

自定義存儲介面 (SessionHandlerInterface)


class MySqlSessionHandler implements SessionHandlerInterface {
    private PDO $pdo;
    
    public function __construct(PDO $pdo) { $this->pdo = $pdo; }
    
    public function open($savePath, $sessionName): bool { return true; }
    public function close(): bool { return true; }
    
    public function read($id): string|false {
        $stmt = $this->pdo->prepare("SELECT data FROM sessions WHERE id = ? AND expiry > ?");
        $stmt->execute([$id, time()]);
        return $stmt->fetchColumn() ?: '';
    }
    
    public function write($id, $data): bool {
        $expiry = time() + ini_get('session.gc_maxlifetime');
        $stmt = $this->pdo->prepare("
            INSERT INTO sessions (id, data, expiry) VALUES (?, ?, ?)
            ON DUPLICATE KEY UPDATE data=VALUES(data), expiry=VALUES(expiry)
        ");
        return $stmt->execute([$id, $data, $expiry]);
    }
    
    public function destroy($id): bool {
        $stmt = $this->pdo->prepare("DELETE FROM sessions WHERE id = ?");
        return $stmt->execute([$id]);
    }
    
    public function gc($maxLifetime): int|false {
        $stmt = $this->pdo->prepare("DELETE FROM sessions WHERE expiry < ?");
        $stmt->execute([time()]);
        return $stmt->rowCount();
    }
}

// 註冊
$handler = new MySqlSessionHandler($pdo);
session_set_save_handler($handler, true); // true = 註冊關閉函數
session_start();

Session 固定攻擊與防護

攻擊場景: 惡意用戶誘導受害者使用已知 Session ID (如發送鏈接 ?PHPSESSID=known_id),受害者登錄後,攻擊者用同 ID 劫持會話。

防護措施:

  1. session.use_strict_mode = 1 (PHP 5.5+):拒絕未由服務器生成的 Session ID。
  2. 登錄成功後 強制重新生成 ID:session_regenerate_id(true) (參數 true 刪除舊文件)。
  3. HTTPS + cookie_secure + cookie_httponly + cookie_samesite。

Session 相關函數速查表

函數用途備註
session_start()啟動/恢復會話必須在輸出前調用
session_regenerate_id(true)生成新 ID,可選刪除舊數據登錄/權限變更時必調用
session_id()獲取/設置當前 ID啟動前調用可指定 ID
session_name()獲取/設置 Cookie 名啟動前調用
session_destroy()銷毀服務端數據不刪除客戶端 Cookie
session_unset()清空 $_SESSION 變量不銷毀會話文件
session_write_close()寫入數據並關閉會話長時間腳本中釋放鎖
session_status()獲取狀態 (DISABLED/NONE/ACTIVE)PHP 5.4+
session_encode()序列化 $_SESSION 數據特有格式,非標準 serialize
session_decode()解碼數據填充 $_SESSION配合 encode 使用

最佳實踐總結

  1. 配置先行: 生產環境必配 redis、httponly、secure、strict_mode。
  2. 極小化存儲: Session 僅存 user_id、permissions 等核心標識,業務數據走緩存/數據庫。
  3. 鎖競爭優化: 長耗時操作 (導出報表、視頻轉碼) 調用 session_write_close() 釋放 Session 鎖,允許並發請求。
  4. 分布式一致性: 多服務器環境禁用文件存儲,統一使用 Redis/DB 集中存儲。
  5. 安全審計: 定期檢查 Session 劫持風險,實現異地登錄檢測、設備指紋綁定。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved