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 和儲存空間,而使用者以頂層網站的形式造訪時,也可以使用這些 Cookie 和儲存空間。

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

用途

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

用途包括:

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

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

相較於其他 API 使用 Storage Access 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 有兩種承諾的方法:

這個 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 提示的範例,但其他瀏覽器擁有類似的使用者介面:

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 的 Cookie 限制為 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 標記。

資源