主域 a1.main.com(應用 A)需向子域 b1.test.com(應用 B)共享登錄態或用戶標識。本文詳細講解跨域 Cookie 設置的關鍵參數、瀏覽器同源策略限制、SameSite 屬性影響,並提供生產環境可用的完整解決方案。
<?php
// a1.main.com/main.php
// 1. 設置跨域 Cookie 關鍵參數
$cookieName = 'shared_token';
$cookieValue = 'user_12345_abcdef'; // 實際應為加密簽名的 Token
$expire = time() + 3600; // 1小時
// 關鍵設置解析:
setcookie($cookieName, $cookieValue, [
'expires' => $expire,
'path' => '/', // 整個域名路徑有效
'domain' => 'test.com', // ★ 關鍵:設置為主域(不含子域前綴),所有子域共享
'secure' => true, // ★ 必須:HTTPS 環境下必須為 true
'httponly' => true, // 防止 XSS 竊取(JS 無法讀取)
'samesite' => 'None', // ★ 關鍵:允許跨站請求攜帶 Cookie
], $expire); // 兼容舊版 PHP 參數順序
// 兼容 PHP 7.3 以下版本的寫法
// setcookie($cookieName, $cookieValue, $expire, '/', 'test.com', true, true);
// 最後兩個參數:secure=true, httponly=true
// SameSite=None 需 PHP 7.3+ 或手動設置 header:
// header("Set-Cookie: {$cookieName}={$cookieValue}; expires=" . gmdate('D, d-M-Y H:i:s T', $expire) . "; path=/; domain=test.com; Secure; HttpOnly; SameSite=None");
<?php
// b1.test.com/test.php
// 直接讀取 $_COOKIE 超全局變量
if (isset($_COOKIE['shared_token'])) {
$token = $_COOKIE['shared_token'];
echo "獲取到共享 Token: {$token}";
// 驗證 Token 有效性(解密、檢查簽名、查詢 Redis 等)
// $user = validateToken($token);
} else {
echo "未獲取到共享 Cookie,可能原因:\n";
echo "1. 用戶未訪問過 a1.main.com\n";
echo "2. 瀏覽器阻止第三方 Cookie(隱私模式、設置)\n";
echo "3. SameSite 策略攔截\n";
echo "4. 域名設置不匹配\n";
}
| 設置值 | 作用範圍 | 示例 |
|---|---|---|
| 未設置 / 當前域 | 僅當前精確域名 | a1.main.com → 僅 a1.main.com |
| .main.com / main.com | 主域及所有子域 | main.com → a1.main.com, b2.main.com 等 |
| test.com | test.com 及所有子域 | test.com → b1.test.com, api.test.com 等 |
規則: Domain 必須是當前域的父域或自身。a1.main.com 可設置 main.com,但不可設置 test.com(不同主域)。跨主域共享需通過 OAuth、JWT、或服務端同步會話實現。
| 值 | 行為 | 跨域場景 |
|---|---|---|
| Strict | 僅第一方請求攜帶(地址欄輸入、書籤) | ❌ 完全阻止 |
| Lax(默認) | 第一方 + 安全頂級導航(鏈接跳轉、GET 表單) | ⚠️ 僅鏈接跳轉可用,AJAX/iframe 被阻 |
| None | 所有請求攜帶(需配合 Secure) | ✅ 完全支持 |
關鍵限制: SameSite=None 必須 配合 Secure=true(HTTPS),否則瀏覽器會拒絕設置。
document.cookie),防禦 XSS
用戶訪問 a1.main.com/main.php
│
▼
服務端設置 Set-Cookie:
shared_token=xxx; Domain=test.com; Path=/; Secure; HttpOnly; SameSite=None
│
▼
瀏覽器存儲 Cookie(域鍵:.test.com)
│
▼
用戶點擊鏈接訪問 b1.test.com/test.php
│
▼
瀏覽器自動攜帶 Cookie 發送請求
│
▼
應用 B 讀取 $_COOKIE['shared_token'] → 驗證 → 識別用戶
| 現象 | 可能原因 | 排查步驟 |
|---|---|---|
| Cookie 未設置成功 | Domain 設置錯誤(非父域) | 檢查 Domain 值是否為當前域的父域 |
| 跨域請求未攜帶 Cookie | SameSite=Lax/Strict 攔截 | 設置 SameSite=None + Secure=true |
| HTTPS 環境下仍失效 | 證書不受信任/自簽名 | 使用有效 CA 證書,瀏覽器無警告 |
| 隱私模式/無痕模式失效 | 瀏覽器阻止第三方 Cookie | 引導用戶調整設置,或改用 OAuth/JWT |
| Safari/IE 兼容問題 | 舊版瀏覽器不支持 SameSite=None | User-Agent 判斷降級策略,或棄用跨域 Cookie |
由於瀏覽器隱私策略收緊(ITP、第三方 Cookie 逐步淘汰),推薦採用:
<?php
// 登錄後生成 JWT
$payload = ['uid' => 123, 'exp' => time() + 3600];
$jwt = JWT::encode($payload, $secretKey);
// 前端存儲在 localStorage/sessionStorage
// 跨域請求時手動添加 Header
fetch('https://b1.test.com/api', {
headers: { 'Authorization': 'Bearer ' + jwt }
});
<?php
// 兩應用配置相同的 Session 存儲
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://redis-server:6379?auth=password');
// 設置相同的 session.name 和 cookie.domain
ini_set('session.name', 'APP_SESSION');
ini_set('session.cookie_domain', '.test.com'); // 共享父域
// 同一用戶訪問任一應用,Session 即共享
Domain=父域、SameSite=None、Secure=true、HttpOnly=true 四項全開