瀏覽器、使用者設定和儲存空間分割功能會封鎖第三方 Cookie,這對依賴嵌入式情境中 Cookie 和其他儲存空間的網站和服務而言,會造成使用者體驗上的挑戰,例如驗證。Storage Access API (SAA) 可讓這些用途繼續運作,同時盡可能限制跨網站追蹤。
導入狀態
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,以便與其他 API 進行比較。這項功能適用於下列兩種情況:
- 使用者會與嵌入的內容互動,也就是說,這不是被動 iframe 或隱藏 iframe。
- 使用者在頂層情境中造訪嵌入的來源,也就是該來源未嵌入其他網站時。
您可以運用各種用途的替代 API:
- 具有獨立分區狀態的 Cookie (CHIPS) 可讓開發人員選擇將 Cookie 納入「分區」儲存空間,每個頂層網站都有一個 Cookie 罐。舉例來說,第三方網路即時通訊小工具可能會設定 Cookie 來儲存工作階段資訊。系統會為每個網站儲存工作階段資訊,因此在嵌入小工具的其他網站上,系統不需要存取小工具設定的 Cookie。如果嵌入的第三方小工具需要在不同來源之間共用相同資訊 (例如登入工作階段的詳細資料或偏好設定),Storage Access API 就會派上用場。
- 儲存空間分割是一種跨網站 iframe 使用現有 JavaScript 儲存機制,同時將每個網站的基礎儲存空間分割開來的方式。這樣可避免某個網站中的嵌入式儲存空間遭到其他網站上的相同嵌入內容存取。
- 相關網站組合 (RWS) 是指機構宣告網站之間的關係,以便瀏覽器允許未分割的 Cookie 和儲存空間存取權,用於特定用途。網站仍需使用 Storage Access API 要求存取權,但如果網站位於該組中,則可在未經使用者提示的情況下授予存取權。
- 聯合憑證管理 (FedCM) 是聯合身分識別服務的隱私權保護方法。Storage Access API 會處理登入後存取未分割的 Cookie 和儲存空間。在某些用途上,FedCM 可做為 Storage Access API 的替代方案,且由於其提供更以登入為導向的瀏覽器提示,因此可能更適合使用。不過,採用 FedCM 通常需要對程式碼進行額外變更,例如支援 HTTP 端點。
- 反詐欺、廣告相關和評估 API 也存在,而 Storage Access API 並非用來解決這些問題。
使用 Storage Access API
Storage Access API 有兩種以承諾為基礎的方法:
Document.hasStorageAccess()
(自 Chrome 125 起,也以新名稱Document.hasUnpartitionedCookieAccess()
提供)Document.requestStorageAccess()
並整合 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 內的同源導覽中保留,特別是針對需要在 HTML 文件的初始要求中提供 Cookie 的網頁,授權後才能重新載入。
使用 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 也類似:
在某些情況下,瀏覽器可能會略過提示,並自動提供權限:
- 如果您在接受提示後,過去 30 天內曾使用該網頁和 iframe。
- 如果嵌入的 iframe 是相關網站組合的一部分。
- 如果 FedCM 用於儲存空間存取權的信任信號。
- 在 Firefox 中,如果您曾在頂層與某個網站互動,該網站在前五次嘗試時也會略過提示。
或者,在某些情況下,方法可能會自動遭到拒絕,而不會顯示提示訊息:
- 如果使用者先前未造訪並與擁有 iframe 的網站互動,而該網站是頂層文件,而不是 iframe。也就是說,Storage Access API 只適用於使用者先前在第一方環境中造訪的嵌入式網站。
- 如果在使用者互動事件之外呼叫
requestStorageAccess()
方法,且未事先在互動後核准提示。
雖然使用者會在首次使用時收到提示,但後續造訪時,Chrome 和 Firefox 會在沒有提示或使用者互動情況下,解決 requestStorageAccess()
。請注意,Safari 一律需要使用者互動。
由於 Cookie 和儲存空間存取權可能在未顯示提示或使用者互動情況下授予,因此在使用者與支援此功能的瀏覽器 (Chrome 和 Firefox) 互動前,通常可以透過在網頁載入時呼叫 requestStorageAccess()
,取得未分割的 Cookie 或儲存空間存取權。這樣一來,您就能立即存取未分割的 Cookie 和儲存空間,並提供更完整的體驗,甚至在使用者與 iframe 互動之前即可。在某些情況下,這可能比等待使用者互動更能提供良好的使用者體驗。
FedCM 做為 SAA 的信任信號
FedCM (聯合憑證管理) 是一種隱私權保護方法,可用於不依賴第三方 Cookie 或導覽重新導向的聯合身分服務 (例如「使用...登入」)。
當使用者登入已嵌入第三方識別資訊提供者 (IdP) 內容的依賴方 (RP),且該內容已透過 FedCM 進行分割時,嵌入的 IdP 內容即可自動取得自身頂層未分割 Cookie 的儲存空間存取權。如要使用 FedCM 啟用自動儲存空間存取權,必須符合下列條件:
- FedCM 驗證 (使用者登入狀態) 必須處於有效狀態。
- RP 已設定
identity-credentials-get
權限,例如:
<iframe src="https://idp.example" allow="identity-credentials-get"></iframe>
例如,idp.example
iframe 嵌入 rp.example
。當使用者透過 FedCM 登入時,idp.example
iframe 可以要求存取其本身頂層 Cookie 的權限。
rp.example
會發出 FedCM 呼叫,透過身分提供者 idp.example
登入使用者:
// The user will be asked to grant FedCM permission.
const cred = await navigator.credentials.get({
identity: {
providers: [{
configURL: 'https://idp.example/fedcm.json',
clientId: '123',
}],
},
});
使用者登入後,只要 RP 已透過權限政策明確允許,IdP 即可從 idp.example
iframe 中呼叫 requestStorageAccess()
。嵌入內容會自動獲得自身頂層 Cookie 的儲存空間存取權,無須使用者啟用或需要其他權限提示:
// Make this call within the embedded IdP iframe:
// No user gesture is needed, and the storage access will be auto-granted.
await document.requestStorageAccess();
// This returns `true`.
const hasAccess = await document.hasStorageAccess();
只要使用者透過 FedCM 登入,系統就會自動授予權限。驗證功能停用後,授予儲存空間存取權時,系統會套用標準 SAA 規定。
使用 storage-access
權限查詢
如要確認是否可以在不經過使用者互動情況下授予存取權,您可以檢查 storage-access
權限的狀態,並在不需要使用者操作的情況下提早呼叫 requestStoreAccess()
,而不是在需要互動時呼叫 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>
Cookie 相關規定
如要透過 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()
方法
requestStorageAccessFor()
方法的運作方式與 requestStorageAccess()
類似,但適用於頂層資源。這項功能只能用於相關網站組合中的網站,以免授予第三方 Cookie 一般存取權。
如要進一步瞭解如何使用 requestStorageAccessFor()
,請參閱「相關網站集:開發人員指南」。
top-level-storage-access
權限查詢
Browser Support
與 storage-access
權限類似,top-level-storage-access
權限可用於檢查是否可授予 requestStorageAccessFor()
存取權。
與 RWS 搭配使用時,Storage Access API 有何不同?
將相關網站組合與 Storage Access API 搭配使用時,您可以使用下表所列的特定額外功能:
未提供 RWS | 使用 RWS | |
---|---|---|
需要使用者手勢才能發起儲存空間存取權要求 | ||
要求使用者在授予存取權前,先在頂層情境中造訪要求的儲存空間來源 | ||
可略過初次使用者提示 | ||
如果先前已授予存取權,則不需要呼叫 requestStorageAccess |
||
自動授予「相關網站」網站中其他網域的存取權 | ||
支援 requestStorageAccessFor 以便存取頂層網頁 |
示範:設定及存取 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 旗標。