SameSite Cookie 食譜

ChromeFirefoxEdge 和其他元件將按照 IETF 提案變更預設行為,改善 Cookie 的增幅,以便:

  • 系統會將沒有 SameSite 屬性的 Cookie 視為 SameSite=Lax;也就是說,預設行為只會限制 Cookie 使用第一方情境
  • 跨網站使用的 Cookie 必須指定 SameSite=None; Secure,才能納入第三方內容。

這項功能是 Chrome 84 日後穩定版的預設行為。建議您更新第三方 Cookie 的屬性,以免日後遭到封鎖。

跨瀏覽器支援

請參閱 MDN Set-Cookie 頁面的「瀏覽器相容性」一節。

跨網站或第三方 Cookie 的用途

在許多常見用途和模式中,Cookie 都必須傳送至第三方環境。如果您提供或依賴其中一種用途,請務必由您或提供者更新 Cookie,以確保服務能繼續正常運作。

<iframe>中的內容

<iframe> 中顯示的其他網站內容,是來自第三方內容。標準用途如下:

  • 其他網站共用的嵌入內容,例如影片、地圖、程式碼範例和社群貼文。
  • 來自外部服務的小工具,例如付款、日曆、預訂和預訂功能。
  • 社交按鈕或反詐欺服務等小工具,會建立較不明顯的 <iframes>

這裡使用 Cookie 來執行其他工作,包括維持工作階段狀態、儲存一般偏好設定、啟用統計資料,或是為現有帳戶的使用者提供個人化內容。

瀏覽器視窗中的圖表,顯示嵌入內容的網址與網頁網址不符。
如果嵌入的內容與頂層瀏覽情境並非來自同一個網站,則視為第三方內容。

此外,由於網路本身是可組合的,因此 <iframes> 可用於嵌入也在頂層或第一方情境中檢視的內容。如果網站在頁框中顯示,網站使用的任何 Cookie 都會被視為第三方 Cookie。如果您打算輕鬆嵌入網站,並讓其他網站使用 Cookie 來運作,您也必須確保這些網站已標記為可跨網站使用,或者可以在不使用 Cookie 的情況下順利將其遞補。

網站的「不安全」要求

「不安全」聽起來可能有些不太在意,但是指任何想要變更狀態的要求。主要使用 POST 要求的網路平台。標示為 SameSite=Lax 的 Cookie 會透過安全的頂層導覽傳送,例如點選連結即可前往其他網站。不過,如果是透過 POST 提交至其他網站的 <form>,就不會包含 Cookie。

從一個頁面移動的要求圖表。
如果傳入的要求採用「安全」方法,系統就會傳送 Cookie。

此模式可用於網站,可能會將使用者重新導向至遠端服務,以便在傳回前執行某些作業,例如重新導向至第三方識別資訊提供者。使用者離開網站前,系統會將內含單一使用權杖的 Cookie 設為包含,並預期可在傳回要求上檢查此權杖,以減輕跨網站要求偽造 (CSRF) 攻擊。如果傳回要求是透過 POST 傳送,則需將 Cookie 標示為 SameSite=None; Secure

遠端資源

網頁上的任何遠端資源可能需要透過 Cookie 隨要求傳送、來自 <img> 標記、<script> 標記等。常見的用途包括追蹤像素和個人化內容。

這也適用於 fetchXMLHttpRequest 透過 JavaScript 發出的要求。如果使用 credentials: 'include' 選項呼叫 fetch(),表示這類要求可能會預期使用 Cookie。針對 XMLHttpRequest,您應該尋找設為 truewithCredentials 屬性例項。這也是良好跡象,表示這些要求應該可以正常使用 Cookie。這些 Cookie 必須正確標記,以納入跨網站要求中。

WebView 中的內容

平台專用應用程式中的 WebView 是由瀏覽器提供支援,您必須測試是否套用相同限製或問題。在 Android 中,如果 WebView 是由 Chrome 提供,則新的預設設定「不會」立即套用至 Chrome 84。然而,意圖在日後套用,因此您仍應進行測試,並做好萬全準備。此外,Android 允許自家平台專用的應用程式透過 CookieManager API 直接設定 Cookie。和透過標頭或 JavaScript 設定的 Cookie 一樣,如果 Cookie 適合跨網站使用,請考慮加入 SameSite=None; Secure

如何立即導入 SameSite

如果 Cookie 只需要第一方結構定義需要使用 Cookie,建議您根據需求將其標示為 SameSite=LaxSameSite=Strict。您也可以選擇不執行任何動作,只讓瀏覽器強制執行預設值,不過這可能會導致瀏覽器發生行為不一致的風險,並針對每個 Cookie 的控制台顯示警告。

Set-Cookie: first_party_var=value; SameSite=Lax

如果是需要第三方內容的 Cookie,您需要確保這些 Cookie 已標示為 SameSite=None; Secure。請注意,您需要一併使用這兩項屬性。如果您只在未指定 Secure 的情況下指定 None,則 Cookie 會遭到拒絕。不過,瀏覽器實作程序有一些互不相容的差異,因此您可能需要使用下方「處理不相容的用戶端」一節所述的一些緩解策略。

Set-Cookie: third_party_var=value; SameSite=None; Secure

處理不相容的用戶端

由於納入 None 和更新預設行為的變更仍然相對新,因此瀏覽器之間也有不一致的設定變更的處理方式。您可以參閱 chromium.org 上的更新頁面瞭解目前已知的問題,但無法確認是否完整。雖然這個方法不理想,但您可以在這個過渡階段中使用可行的解決方法。但一般會將不相容的用戶端視為特殊情況。請勿為執行新版規則的瀏覽器建立例外狀況。

第一種是設定新舊樣式 Cookie:

Set-cookie: 3pcookie=value; SameSite=None; Secure
Set-cookie: 3pcookie-legacy=value; Secure

導入較新行為的瀏覽器會以 SameSite 值設定 Cookie,其他瀏覽器則可能會忽略或設定錯誤。不過,這些相同的瀏覽器都會設定 3pcookie-legacy Cookie。處理包含的 Cookie 時,網站應先檢查新樣式 Cookie 是否存在,如果找不到,然後再改用舊版 Cookie。

以下範例說明如何在 Node.js 中執行此操作,並利用 Express 架構及其 cookie-parser 中介軟體。

const express = require('express');
const cp = require('cookie-parser');
const app = express();
app.use(cp());

app.get('/set', (req, res) => {
  // Set the new style cookie
  res.cookie('3pcookie', 'value', { sameSite: 'none', secure: true });
  // And set the same value in the legacy cookie
  res.cookie('3pcookie-legacy', 'value', { secure: true });
  res.end();
});

app.get('/', (req, res) => {
  let cookieVal = null;

  if (req.cookies['3pcookie']) {
    // check the new style cookie first
    cookieVal = req.cookies['3pcookie'];
  } else if (req.cookies['3pcookie-legacy']) {
    // otherwise fall back to the legacy cookie
    cookieVal = req.cookies['3pcookie-legacy'];
  }

  res.end();
});

app.listen(process.env.PORT);

但缺點是,必須設定備援 Cookie 來涵蓋所有瀏覽器,而且必須在設定及讀取 Cookie 的時間點進行變更。不過,無論瀏覽器行為為何,這項做法應涵蓋所有瀏覽器,並確保第三方 Cookie 繼續照常運作。

或者,您也可以在傳送 Set-Cookie 標頭的時間點,選擇透過使用者代理程式字串偵測用戶端。請參閱不相容的用戶端清單,然後針對您的平台使用適當程式庫,例如 Node.js 上的 ua-parser-js 程式庫。建議您尋找程式庫來處理使用者代理程式的偵測作業,因為您可能不想自行編寫這些規則運算式。

此方法的好處是只需要在設定 Cookie 時進行一次變更。不過,此處必要的警告是,使用者代理程式的探查功能本來就很脆弱,而且可能無法捕捉到所有受影響的使用者。

支援多種語言、程式庫和架構中的 SameSite=None

絕大多數的語言和程式庫都支援 Cookie 的 SameSite 屬性,但新增的 SameSite=None 仍相對新,這表示您可能目前可能需要處理一些標準行為。相關詳情請參閱 GitHub 上的 SameSite 範例存放區

取得協助

Cookie 遍布到處,很少有網站能完全檢查其設定及使用位置,尤其在混合出現跨網站用途時更是如此。當您遇到問題時,我們可能是第一次遇到其他人遇到的問題,因此歡迎隨時與我們聯絡: