SameSite Cookie 食譜

ChromeFirefoxEdge 和其他瀏覽器都會根據 IETF 提案「Incrementally Better Cookies」調整預設行為,以便:

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

如果您尚未這麼做,請更新第三方 Cookie 的屬性,以免日後遭到封鎖。

瀏覽器支援

  • Chrome:51。
  • 邊緣:16。
  • Firefox:60。
  • Safari:13。

資料來源

跨網站或第三方 Cookie 的用途

有許多常見用途和模式需要在第三方情境中傳送 Cookie。如果您提供或依賴其中一種用途,請務必確保您或供應商會更新 cookie,以便服務正常運作。

<iframe> 內的內容

<iframe> 中顯示的不同網站內容屬於第三方內容。標準用途包括:

  • 從其他網站分享的嵌入內容,例如影片、地圖、程式碼範例和社群媒體貼文。
  • 來自外部服務的資訊方塊,例如付款、日曆、預訂和預約功能。
  • 小工具 (例如社群媒體按鈕或防詐欺服務),這些小工具會產生較不明顯的<iframes>

這類 Cookie 可用於維持工作階段狀態、儲存一般偏好設定、啟用統計資料,或為現有帳戶使用者提供個人化內容。

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

由於網頁本質上是可組合的,<iframes> 也用於在頂層或第一方情境中嵌入內容。在 iframe 中顯示的網站使用任何 Cookie 都會視為第三方 Cookie。如果您要建立其他網站可嵌入的網站,且需要 Cookie 才能正常運作,也請務必將這些網站標示為跨網站使用,或在沒有 Cookie 的情況下,能順利回復。

跨網站的「不安全」要求

「Unsafe」聽起來可能令人擔心,但它是指任何可能會變更狀態的要求。在網路上,這通常是 POST 要求。標示為 SameSite=Lax 的 Cookie 會在安全的頂層導覽 (例如點按連結前往其他網站) 時傳送。不過,使用 POST 將 <form> 提交至其他網站的操作不會包含 Cookie。

圖表:要求從一個網頁移動到另一個網頁。
如果傳入的要求使用「安全」方法,頁面會傳送 Cookie。

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

遠端資源

網頁上的任何遠端資源 (例如 <img> 標記或 <script> 標記) 都可能會依賴透過請求傳送的 Cookie。常見用途包括追蹤像素和個人化內容。

這項規定也適用於使用 fetchXMLHttpRequest 從 JavaScript 傳送的要求。如果 fetch() 是使用 credentials: 'include' 選項 呼叫,這些要求可能會包含 Cookie。對於 XMLHttpRequest,預期 Cookie 通常會透過 truewithCredentials表示。這些 Cookie 必須標示為適當,才能納入跨網站要求。

WebView 中的內容

特定平台應用程式中的 WebView 是由瀏覽器提供動力。開發人員需要測試影響應用程式的限制或問題是否也適用於應用程式的 WebView。

Android 也允許其平台專屬應用程式直接使用 CookieManager API 設定 Cookie。如同使用標頭或 JavaScript 設定的 Cookie,如果 Cookie 是用於跨網站使用,建議您加入 SameSite=None; Secure

如何立即導入 SameSite

視需求將任何僅在第一方情境中需要的 Cookie 標示為 SameSite=LaxSameSite=Strict。如果您未標記這些 Cookie,而是依賴預設瀏覽器行為來處理,這些 Cookie 在不同瀏覽器中的行為可能會不一致,且可能會為每個 Cookie 觸發控制台警告。

Set-Cookie: first_party_var=value; SameSite=Lax

請務必將第三方情境中所需的所有 Cookie 標示為 SameSite=None; Secure。這兩個屬性皆為必要屬性。如果您只指定 None,而未指定 Secure,系統會拒絕 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 程式庫。這個方法只需要您進行一次變更,但使用者代理程式嗅探可能無法捕捉到所有受影響的使用者。

在語言、程式庫和架構中支援 SameSite=None

大多數語言和程式庫都支援 Cookie 的 SameSite 屬性。不過,由於 SameSite=None 的新增功能仍屬於較新的功能,因此您可能需要針對某些標準行為進行調整。這些行為已記錄在 GitHub 上的 SameSite 範例存放區中。

取得說明

網站上到處都會使用 Cookie,但開發團隊很少能完全瞭解網站在何處設定及使用 Cookie,特別是在跨網站使用 Cookie 的情況下。當您遇到問題時,可能是第一次遇到問題,因此歡迎隨時與我們聯絡: