Storage Access API

因為瀏覽器、使用者設定和儲存空間分區而仰賴 Cookie 和其他儲存空間的網站和服務,這對使用者歷程 (例如驗證) 來說往往是一大挑戰。Storage Access API (SAA) 可讓這些用途繼續運作,同時盡可能限制跨網站追蹤。

導入狀態

瀏覽器支援

  • Chrome:119。
  • Edge:85,
  • Firefox:65。
  • Safari:11.1.

資料來源

Storage Access API 可在所有主要瀏覽器中使用,但不同瀏覽器之間實作方式略有不同。本篇文章的相關章節已強調這些差異。

將 API 標準化之前,工作會持續解決所有剩餘的封鎖問題

什麼是 Storage Access API?

Storage Access API 是一種 JavaScript API,可讓 iframe 在瀏覽器設定拒絕存取時要求儲存空間存取權限。嵌入內容的用途如果需要載入跨網站資源,就可以在需要時使用 API 向使用者要求存取權。

如果儲存空間要求獲得核准,iframe 就能存取未分割的 Cookie 和儲存空間,使用者以頂層網站的形式造訪時,也能存取這些資料。

Storage Access API 讓使用者幾乎不用費心存取特定的不分區 Cookie 和儲存空間存取權,同時仍能防止一般未分區的 Cookie 和儲存空間存取行為 (如同使用者追蹤的一般用途)。

用途

有些第三方嵌入項目需要存取未分區的 Cookie 或儲存空間,才能為使用者提供更優質的體驗。如果第三方 Cookie 受限,並啟用儲存空間分區,就無法使用這類功能。

用途包括:

  • 內嵌的註解小工具,需要登入工作階段詳細資料。
  • 社群媒體「喜歡」需要登入工作階段詳細資訊的按鈕。
  • 需要登入工作階段詳細資料的內嵌文件。
  • 為嵌入的影片提供優質體驗 (例如,不向已登入的使用者顯示廣告,或瞭解使用者關於隱藏式輔助字幕的偏好設定,或限制特定類型的影片)。
  • 嵌入式付款系統。

許多這類使用案例都涉及在嵌入式 iframe 中持續登入存取權。

何時應使用 Storage Access API 而非其他 API

Storage Access API 是非分區 Cookie 和儲存空間的替代方案之一,因此,請務必瞭解何時使用此 API。這項功能適用於下列兩種情況:

  • 使用者會與嵌入的內容互動,也就是說,這不是被動 iframe 或隱藏 iframe。
  • 使用者在頂層情境中造訪嵌入的來源,也就是該來源未嵌入其他網站時。

您可以運用各種用途的替代 API:

  • 具有獨立分區狀態的 Cookie (CHIPS) 可讓開發人員選擇將 Cookie 納入「分區」儲存空間,每個頂層網站都有一個獨立的 Cookie Jar。舉例來說,第三方網路即時通訊小工具可能會設定 Cookie 來儲存工作階段資訊。系統會為每個網站儲存工作階段資訊,因此在嵌入小工具的其他網站上,系統不需要存取小工具設定的 Cookie。如果內嵌的第三方小工具需要在不同來源 (例如登入工作階段詳細資料或偏好設定) 之間共用相同資訊,Storage Access API 就相當實用。
  • 儲存空間分區」是跨網站 iframe 使用現有 JavaScript 儲存空間機制的方法,且可分配每個網站的基礎儲存空間。這樣可避免一個網站的嵌入式儲存空間遭到其他網站上的相同嵌入式內容存取。
  • 相關網站組合 (RWS) 是指機構宣告網站之間的關係,以便瀏覽器允許未分割的 Cookie 和儲存空間存取權,用於特定目的。網站仍需使用 Storage Access API 要求存取權,但如果網站位於該組中,則可在未經使用者提示的情況下授予存取權。
  • Federated Credential Management (FedCM) 是聯合身分識別服務的隱私權保護做法。Storage Access API 會處理登入後存取未分割的 Cookie 和儲存空間。在某些用途中,FedCM 可做為 Storage Access API 的替代方案,且由於其提供更以登入為導向的瀏覽器提示,因此可能更適合使用。然而,採用 FedCM 後,程式碼通常需要進行額外的變更,例如支援其 HTTP 端點。
  • 此外,也有反詐騙廣告相關評估 API,而 Storage Access API 並非為處理這些顧慮。

使用 Storage Access API

Storage Access API 有兩種承諾的方法:

並整合 Permissions API。這可讓您檢查第三方情境中的儲存空間存取權狀態,指出是否會自動授予對 document.requestStorageAccess() 的呼叫:

使用 hasStorageAccess() 方法

首次載入網站時,可使用 hasStorageAccess() 方法檢查是否已授予第三方 Cookie 的存取權。

// Set a hasAccess boolean variable which defaults to false.
let hasAccess = false;

async function handleCookieAccessInit() {
  if (!document.hasStorageAccess) {
    // Storage Access API is not supported so best we can do is
    // hope it's an older browser that doesn't block 3P cookies.
    hasAccess = true;
  } else {
    // Check whether access has been granted using the Storage Access API.
    // Note on page load this will always be false initially so we could be
    // skipped in this example, but including for completeness for when this
    // is not so obvious.
    hasAccess = await document.hasStorageAccess();
    if (!hasAccess) {
      // Handle the lack of access (covered later)
    }
  }
  if (hasAccess) {
    // Use the cookies.
  }
}
handleCookieAccessInit();

系統只會在 iframe 文件呼叫 requestStorageAccess(), 後授予儲存空間存取權,因此 hasStorageAccess() 一開始一律會傳回 false,除非同一個 iframe 中的另一個相同來源文件已獲得存取權。這個授權設定會保留在 iframe 內的相同來源瀏覽中,以便系統在將需要 Cookie 的網頁送出存取要求之後,重新載入需要出現在 HTML 文件的網頁,以便重新載入網頁。

使用 requestStorageAccess()

如果 iframe 沒有存取權,可能需要使用 requestStorageAccess() 方法要求存取權:

if (!hasAccess) {
  try {
    await document.requestStorageAccess();
  } catch (err) {
    // Access was not granted and it may be gated behind an interaction
    return;
  }
}

首次要求時,使用者可能需要透過瀏覽器提示核准這項存取權,之後承諾會解析,或會拒絕,導致使用 await 時發生例外狀況。

為防止濫用情形,這項瀏覽器提示只會在使用者互動後顯示。因此,requestStorageAccess() 一開始必須從使用者啟動的事件處理常式呼叫,而非在 iframe 載入時立即呼叫:

async function doClick() {

  // Only do this extra check if access hasn't already been given
  // based on the hasAccess variable.
  if (!hasAccess) {
    try {
      await document.requestStorageAccess();
      hasAccess = true; // Can assume this was true if requestStorageAccess() did not reject.
    } catch (err) {
      // Access was not granted.
      return;
    }
  }

  if (hasAccess) {
    // Use the cookies
  }
}

document.querySelector('#my-button').addEventListener('click', doClick);

如果您需要使用本機儲存空間而非 Cookie,可以執行下列動作:

let handle = null;

async function doClick() {
  if (!handle) {
    try {
      handle = await document.requestStorageAccess({localStorage: true});
    } catch (err) {
      // Access was not granted.
      return;
    }
  }

  // Use handle to access unpartitioned local storage.
  handle.localStorage.setItem('foo', 'bar');
}

document.querySelector('#my-button').addEventListener('click', doClick);

權限提示

使用者第一次按下按鈕時,瀏覽器提示會自動顯示,通常會顯示在網址列中。下圖顯示 Chrome 提示的範例,但其他瀏覽器的 UI 也類似:

Chrome Storage Access API 權限提示
Chrome 的 Storage Access API 權限提示

在某些情況下,瀏覽器可能會略過提示,並自動提供權限:

  • 如果您在接受提示後,過去 30 天內曾使用該網頁和 iframe。
  • 如果嵌入的 iframe 是相關網站組合的一部分。
  • 在 Firefox 中,如果您曾在頂層與某個網站互動,該網站在前五次嘗試時也會略過提示。

或者,在某些情況下,方法可能會自動遭到拒絕,而不會顯示提示訊息:

  • 如果使用者先前未造訪並與擁有 iframe 的網站互動,而該網站是頂層文件,而不是 iframe。也就是說,Storage Access API 只適用於使用者先前在第一方環境中造訪的嵌入式網站。
  • 如果在使用者互動事件後未事先核准提示,即呼叫 requestStorageAccess() 方法。

雖然系統會在初次使用時提示使用者,但之後造訪時,不需要提示或在 Chrome 和 Firefox 中與其互動,就可以解析 requestStorageAccess()。請注意,Safari 一律需要使用者互動。

由於可在沒有提示或與使用者互動的情況下取得 Cookie 和儲存空間的存取權,因此在支援這項機制的瀏覽器 (Chrome 和 Firefox) 上與使用者互動之前,通常可在載入網頁時呼叫 requestStorageAccess(),進而取得未分區的 Cookie 或儲存空間存取權。這可讓您立即存取未分區的 Cookie 和儲存空間,並在使用者與 iframe 互動之前,提供更完整的體驗。在某些情況下,這可能比等待使用者互動更能提供良好的使用者體驗。

使用 storage-access 權限查詢

如要檢查是否能在非使用者互動的情況下授予存取權,您可以檢查 storage-access 權限的狀態,並只在使用者不需要執行任何動作時提早呼叫 requestStoreAccess(),而不是在需要使用者互動時呼叫。

您也可以透過顯示其他內容 (例如登入按鈕),提前處理提示的需求。

以下程式碼會在先前的範例中加入 storage-access 權限檢查:

// Set a hasAccess boolean variable which defaults to false except for
// browsers which don't support the API - where we assume
// such browsers also don't block third-party cookies.
let hasAccess = false;

async function hasCookieAccess() {
  // Check if Storage Access API is supported
  if (!document.requestStorageAccess) {
    // Storage Access API is not supported so best we can do is
    // hope it's an older browser that doesn't block 3P cookies.
    return true;
  }

  // Check if access has already been granted
  if (await document.hasStorageAccess()) {
    return true;
  }

  // Check the storage-access permission
  // Wrap this in a try/catch for browsers that support the
  // Storage Access API but not this permission check
  // (e.g. Safari and earlier versions of Firefox).
  let permission;
  try {
    permission = await navigator.permissions.query(
      {name: 'storage-access'}
    );
  } catch (error) {
    // storage-access permission not supported. Assume no cookie access.
    return false;
  }

    if (permission) {
    if (permission.state === 'granted') {
      // Permission has previously been granted so can just call
      // requestStorageAccess() without a user interaction and
      // it will resolve automatically.
      try {
        await document.requestStorageAccess();
        return true;
      } catch (error) {
        // This shouldn't really fail if access is granted, but return false
        // if it does.
        return false;
      }
    } else if (permission.state === 'prompt') {
      // Need to call requestStorageAccess() after a user interaction
      // (potentially with a prompt). Can't do anything further here,
      // so handle this in the click handler.
      return false;
          } else if (permission.state === 'denied') {
            // Not used: see https://github.com/privacycg/storage-access/issues/149
      return false;
          }
    }

  // By default return false, though should really be caught by earlier tests.
  return false;
}

async function handleCookieAccessInit() {
  hasAccess = await hasCookieAccess();

  if (hasAccess) {
    // Use the cookies.
  }
}

handleCookieAccessInit();

採用沙箱機制的 iframe

沙箱 iframe 中使用 Storage Access API 時,需要下列沙箱權限:

  • 需要 allow-storage-access-by-user-activation 才能允許存取 Storage Access API。
  • 必須使用 allow-scripts 才能使用 JavaScript 呼叫 API。
  • allow-same-origin 必須允許存取相同來源的 Cookie 和其他儲存空間。

例如:

<iframe sandbox="allow-storage-access-by-user-activation
                 allow-scripts
                 allow-same-origin"
        src="..."></iframe>

如要在 Chrome 中使用 Storage Access API 存取,跨網站 Cookie 必須設定下列兩個屬性:

  • SameSite=None - 必須將 Cookie 標示為跨網站
  • Secure:確保只能存取由 HTTPS 網站設定的 Cookie。

在 Firefox 和 Safari 中,Cookie 預設為 SameSite=None,且不會將 SAA 限制為 Secure Cookie,因此不需要這些屬性。建議您清楚說明 SameSite 屬性,並一律使用 Secure Cookie。

頂層網頁存取權

Storage Access API 可讓您在嵌入式 iframe 中存取第三方 Cookie。

頂層頁面也需要存取第三方 Cookie,還有其他用途。舉例來說,圖片或腳本受 Cookie 限制,網站管理員可能會直接將其納入頂層文件,而非 iframe。為因應這類用途,Chrome 已提出Storage Access API 擴充功能,其中新增了 requestStorageAccessFor() 方法。

requestStorageAccessFor() 方法

瀏覽器支援

  • Chrome:119。
  • Edge:119。
  • Firefox:不支援。
  • Safari:不支援。

資料來源

requestStorageAccessFor() 方法的運作方式與 requestStorageAccess() 類似,但適用於頂層資源。這項功能只能用於相關網站集中的網站,以防止一般使用者存取第三方 Cookie。

如要進一步瞭解如何使用 requestStorageAccessFor(),請參閱「相關網站集:開發人員指南」。

top-level-storage-access 權限查詢

瀏覽器支援

  • Chrome:不支援。
  • Edge:不支援。
  • Firefox:不支援。
  • Safari:不支援。

storage-access 權限類似,top-level-storage-access 權限可用於檢查是否可授予 requestStorageAccessFor() 存取權。

與 RWS 搭配使用時,Storage Access API 有何不同?

將相關網站組合與 Storage Access API 搭配使用時,您可以使用下表所列的特定額外功能:

未提供 RWS 配備 RWS
需透過使用者手勢來啟動儲存空間存取權要求
要求使用者在授予存取權前,先在頂層情境中造訪要求的儲存空間來源
略過首次使用者提示
如果先前已授予存取權,則不必呼叫 requestStorageAccess
自動授予相關網站網站中其他網域的存取權
支援 requestStorageAccessFor 以便存取頂層網頁
使用 Storage Access API 時,是否使用相關網站集的差異

示範:設定及存取 Cookie

以下示範示範您在示範第一個畫面設定的 Cookie,如何在示範過程第二個網站的內嵌頁框中存取:

storage-access-api-demo.glitch.me

您需要停用第三方 Cookie 的瀏覽器,才能進行這項示範:

  • Chrome 118 以上版本,並設定 chrome://flags/#test-third-party-cookie-phaseout 標記並重新啟動瀏覽器。
  • Firefox
  • Safari

示範:設定本機儲存空間

以下示範如何使用 Storage Access API 從第三方 iframe 存取未分割的廣播管道:

https://saa-beyond-cookies.glitch.me/

這個示範需要 Chrome 125 以上版本,並啟用 test-third-party-cookie-phaseout 旗標。

資源