SameSite Cookie 食譜

ChromeFirefoxEdge 等瀏覽器正根據 IETF 提案「Incrementally Better Cookies」 變更預設行為, 以便:

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

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

Browser Support

  • Chrome: 51.
  • Edge: 16.
  • Firefox: 60.
  • Safari: 13.

Source

跨網站或第三方 Cookie 的用途

在許多常見用途和模式中,Cookie 都必須在第三方環境中傳送。如果您提供或依賴其中一個用途,請確保您或供應商會更新 Cookie,讓服務正常運作。

<iframe> 內的內容

<iframe> 中顯示其他網站的內容時,會處於第三方環境。常見用途包括:

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

我們可能會在此使用 Cookie,以便維護工作階段狀態、儲存一般偏好設定、啟用統計資料,或為現有帳戶使用者提供個人化內容。

瀏覽器視窗的示意圖,內嵌內容的網址與網頁網址不符。
如果嵌入的內容並非來自與頂層瀏覽環境相同的網站,就是第三方內容。

由於網頁本質上是可組合的,<iframes> 也可用於嵌入在頂層或第一方情境中檢視的內容。網站在 iframe 中顯示的任何 Cookie 都視為第三方 Cookie。如果您要建立可供其他網站嵌入的網站,且需要 Cookie 才能運作,也必須確保這些 Cookie 已標示為可供跨網站使用,或確保沒有這些 Cookie 時,網站仍可正常運作。

跨網站的「不安全」要求

「不安全」聽起來可能令人擔憂,但這裡是指任何可能要變更狀態的要求。在網路上,這主要是指 POST 要求。系統會在安全的頂層導覽中傳送標示為 SameSite=Lax 的 Cookie,例如點選連結前往其他網站。不過,如果使用 POST 將內容<form>提交至其他網站,就不會包含 Cookie。

要求從一個網頁移至另一個網頁的示意圖。
如果傳入的要求使用「安全」方法,網頁會傳送 Cookie。

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

遠端資源

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

使用 fetchXMLHttpRequest 從 JavaScript 傳送的要求也適用這項規定。如果使用credentials: 'include' 選項呼叫 fetch(),這些要求可能會包含 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 的位置,尤其是在跨網站用途中。您遇到的問題可能是前所未見,因此請務必回報: