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

PHP Cookie 完全指南:設置、跨域、安全與最佳實踐

     編輯:PHP 綜合知識

Cookie 基礎概念

Cookie 是 HTTP 協議下服務端在客戶端瀏覽器存儲的小型文本數據(≤4KB),隨後續同域請求自動攜帶,實現「無狀態 HTTP」的狀態感知。PHP 通過 setcookie() 發送 Set-Cookie 響應頭,自動將接收到的 Cookie 解析為 $_COOKIE 超全局數組。

setcookie() 完整語法與參數詳解

setcookie(
    string $name,
    string $value = "",
    int $expires_or_options = 0,
    string $path = "",
    string $domain = "",
    bool $secure = false,
    bool $httponly = false
): bool

// PHP 7.3+ 支持選項數組寫法(推薦)
setcookie('name', 'value', [
    'expires' => time() + 3600,
    'path' => '/',
    'domain' => '.example.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);
參數說明注意事項
nameCookie 名稱,即鍵名避免使用中文/特殊字符,建議 ASCII 可打印字符
valueCookie 值自動 urlencode,取值時自動 urldecode;勿存敏感明文
expiresUnix 時間戳過期時間;0 或省略 = 會話級(瀏覽器關閉失效)用 time()+86400*30 表示 30 天;勿用未來固定日期,客戶端時間可能不準
path生效路徑前綴預設當前腳本目錄;通常設 / 全站生效
domain生效域名需包含至少兩個點(如 .example.com);不帶點僅當前主機名
secure僅 HTTPS 傳輸生產環境必開 true
httponlyJS 不可讀(document.cookie 不可見)必開 true,防 XSS 竊取 Session ID
samesite跨站攜帶策略:Strict/Lax/NoneLax 平衡體驗與安全;None 必配合 secure=true

實戰案例:用戶識別與訪問計數

<?php
// 1. 讀取/解析 Cookie
$cookieName = 'user_track';
$data = $_COOKIE[$cookieName] ?? '';
$parts = explode('|', $data, 4); // name|email|visits|last_visit

if ($data !== '') {
    // 老用戶:更新計數與時間
    [$name, $email, $visits, $last] = $parts;
    $visits = (int)$visits + 1;
    $newData = implode('|', [$name, $email, $visits, time()]);
    setcookie($cookieName, $newData, [
        'expires' => time() + 86400 * 365,
        'path' => '/',
        'httponly' => true,
        'secure' => isset($_SERVER['HTTPS']),
        'samesite' => 'Lax',
    ]);
    echo "歡迎回來,$name!第 $visits 次訪問。";
} else {
    // 新用戶:引導註冊
    echo '<a href="register.php">立即註冊</a>';
}

// register.php 處理邏輯略...
?>

跨域 Cookie 解決方案(同主域不同子域)

場景:app.example.com 登錄後,需在 shop.example.com 保持登錄態。

方案一:父域 Cookie(最簡單、推薦)

// 登錄服務設置 Cookie
setcookie('sid', $sessionId, [
    'expires' => time() + 86400 * 30,
    'path' => '/',
    'domain' => '.example.com', // 關鍵:以點開頭,覆蓋所有子域
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);

所有 *.example.com 子域請求自動攜帶此 Cookie。

方案二:跨域傳遞 Session ID + 服務端共享存儲(不同主域)

適用於 example.com 與 another.com 完全不同域。

  1. 統一 Session 存儲:雙方連接同一 Redis/DB,Session 數據共享
  2. 登錄時生成 Token:$token = bin2hex(random_bytes(32)),存入共享存儲
  3. 跳轉攜帶 Token:header("Location: https://another.com/sso?token=$token")
  4. 目標域驗證 Token:查共享存儲,有效則建立本地 Session,並設置本域 Cookie
  5. 清理 Token:一次性使用後刪除,防重放

此為簡易 SSO(單點登錄)模型,生產環境建議用成熟協議(OAuth2/OIDC/SAML)。

方案三:舊文檔中的 URL 重寫方案(不推薦)

原文通過 Apache mod_rewrite 將 /-token-/path 重寫為 /path?sessionid=token,再由 PHP 讀取 $_GET['sessionid'] 手動 session_id()。缺點:URL 洩露 Session ID、日誌記錄風險、SEO 不友好、移動端體驗差。現代瀏覽器對第三方 Cookie 限制日益收緊,建議棄用。

安全最佳實踐清單

  1. 敏感數據不入 Cookie:用戶 ID、權限、Token 雜湊值僅存服務端 Session/Redis
  2. 簽名/加密 Cookie 值:如需在 Cookie 存業務數據,使用 hash_hmac('sha256', $data, $secret) 簽名,或 openssl_encrypt() 加密,防篡改
  3. 設置 SameSite=Lax 以上:緩解 CSRF,關鍵操作再加雙重 Token
  4. 定期輪換 Session ID:登錄、權限變更、敏感操作前 session_regenerate_id(true)
  5. 限制 Cookie 作用域:path、domain 最小化,減少洩露面
  6. 監控異常 Cookie:WAF 檢測超長、異常編碼、注入特徵的 Cookie

常見問題排查

現象可能原因排查步驟
Cookie 不生效1. setcookie() 前有輸出 2. 域/路徑不匹配 3. 瀏覽器阻止第三方 Cookie 4. secure=true 但 HTTP 訪問檢查響應頭 Set-Cookie;開發者工具 Application 面板查看;curl -I 驗證
跨域不共享1. domain 設置錯誤 2. SameSite=Strict 阻止 3. 瀏覽器第三方 Cookie 策略確認父域語法;嘗試 Lax/None+Secure;遷移至 SSO 方案
中文亂碼值未 urlencode 或雙重編碼PHP 自動編碼/解碼,勿手動 urlencode;存 JSON 時用 json_encode($arr, JSON_UNESCAPED_UNICODE)
無法刪除刪除時 path/domain/secure 必須與設置時完全一致用相同參數 setcookie('name', '', time()-3600, ...)

結語

Cookie 是 Web 狀態管理的基石,但也是攻擊面重災區。遵循「最小權限、服務端信任、簽名驗證、HTTPS 強制」原則,配合現代 SameSite 屬性,即可在便利與安全間取得平衡。跨域場景優先選父域 Cookie 或標準 SSO 協議,避免陷入 URL 重寫等過時方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved