儲存空間分割會依嵌入網站與頂層頁面雙重索引瀏覽器狀態,讓同一個小工具在兩個網站上,各自取得一個互不相通、無法互相窺探的儲存空間。
在網路發展史的大部分時間裡,瀏覽器回答「這段程式碼該拿到哪一份儲存空間?」這個問題時,只看一件事:程式碼來自哪個來源(origin)。因此,一個嵌在一百個網站上的追蹤小工具,在這一百個網站上讀寫的都是同一份 Cookie 儲存,而這份共用的儲存,正是讓跨站追蹤成本如此低廉的原因。**儲存空間分割(storage partitioning)**換了一種問法。現在儲存空間會用兩把鑰匙來建立索引——擁有它的來源,以及你實際造訪的頂層網站——所以同一個嵌入小工具出現在兩個不同的網站上,會拿到兩個互不相干、彼此看不見的儲存空間。
核心要點
- 核心概念就是雙重索引。 瀏覽器不再只依資源的來源來建立狀態索引,而是依 (資源來源,頂層網站) 這一對來建立。MDN 的狀態分割(State Partitioning)指南把 Firefox 的做法描述為「依所載入資源的來源與頂層網站,對所有用戶端狀態進行雙重索引」。
- 同一個嵌入元件出現在兩個網站上,代表兩個儲存空間,而不是一個。 嵌在
A.example與B.example上的追蹤者,再也無法在一處存下 ID、又在另一處讀回來;它在 A 網站上看到的資料,和在 B 網站上看到的並不相同。 - 「Cookie」只是涵蓋範圍的一部分。 分割同時涵蓋
localStorage、sessionStorage、IndexedDB、Cache API、Service Worker,以及 HTTP 快取這類網路狀態——而且各家瀏覽器引擎分割的項目與方式並不完全相同。 - Storage Access API 是刻意保留的逃生出口。 嵌入的頁框可以在使用者操作之後呼叫
requestStorageAccess(),取回它一般的第一方 Cookie,但這項授權只限定於某一組(頂層網站,嵌入網站)配對,並不是全域開啟。 - 分割打斷的是以狀態為基礎的跨站追蹤,而不是追蹤本身。 指紋不需要任何儲存空間,所以沒有東西可以分割——這也是為什麼這項改變讓指紋對追蹤者來說更有價值,而不是更沒價值。
「雙重索引」究竟是什麼意思
瀏覽器傳統上是依資源載入位置的來源(有時是可註冊網域)來建立用戶端狀態的索引。MDN 舉了一個典型的例子:從 https://example.com/hello.html 載入的 iframe 所能取用的 Cookie、localStorage 物件與快取,都是以 example.com 作為索引。不管瀏覽器是把 example.com 當成你正在瀏覽的頁面(第一方)來載入,還是當成嵌在別人頁面裡的內容(第三方)來載入,這一點都成立。
追蹤者利用的正是這一點。把一個 example.com 的 iframe 或指令碼放在 A.example 與 B.example 上,把使用者識別碼存進它的 Cookie 或 localStorage,它就能在兩個網站上讀回同一個識別碼。兩個網站之間不需要任何串通;共用的儲存空間本身就完成了串連。
分割加上了第二把鑰匙。第一把鑰匙依舊是所載入資源的來源,第二把則是頂層網站——多數情況下,就是網址列上那個頁面的協定加上可註冊網域。當 example.com 被嵌在兩個網站裡時,會產生這樣的結果:
| 程式碼執行的位置 | 取得的儲存空間 |
|---|---|
直接造訪 example.com | (example.com,example.com) |
example.com 嵌入在 A.example | (example.com,A.example) |
example.com 嵌入在 B.example | (example.com,B.example) |
也就是說,原本的一個儲存空間變成了三個各自獨立的儲存空間。追蹤者仍然有儲存空間可用——只是無法把識別碼從第一個帶進另外兩個。在直接造訪時存下的 ID,不能再於嵌入其他網站時被取回。
請留意沒有改變的部分:在 example.com 本身、一般的分頁裡,一切運作如常。分割只有在程式碼於第三方情境中執行時才會生效。
哪些東西會被分割(不只有 Cookie)
最常見的誤解,是把它當成「第三方 Cookie 攔截換了個名字」。其實這是不同的做法。較舊的政策是在第三方情境中封鎖某些儲存 API 的存取;分割則是替嵌入內容在每個頂層網站底下提供一個獨立的儲存空間,所以不需要封鎖任何東西,隔離就能成立。
MDN 的 Firefox 文件把這個範圍分成三組:
| 群組 | 範例 | 在 Firefox 中的行為 |
|---|---|---|
| 可存取的儲存空間 | localStorage、sessionStorage、DOM Cache、IndexedDB、Broadcast Channel、Shared Workers、Service Workers | 依頂層網站分割 |
| Cookie | 第三方 Cookie | 預設分割,但有辦法取回未分割的存取權(見下文) |
| 網路狀態 | HTTP 快取、圖片快取、favicon 快取、連線池、DNS、HSTS、TLS 工作階段識別碼、OCSP、字型 | 永久分割;網站無法放寬 |
網路狀態這一列對隱私之所以重要,是因為這些機制原本從來就不是用來儲存資料的,卻可能被濫用成儲存空間。ETag 與快取超級 Cookie用的正是這個把戲:某個網站能設定、另一個網站又能讀回的快取回應,就是一條追蹤通道。依頂層網站來分割 HTTP 快取,就封死了它的跨站版本。
各家瀏覽器引擎的現況
坦白說,並不存在單一的「網頁平台」狀態,因為各家引擎是各自、在不同的時間點採行分割的。以下內容僅限於原始資料來源所記載的部分;任何版本號碼,都請對照最新的文件重新確認。
- **Safari(WebKit)**最早動手。它在 2017 年推出的智慧型追蹤防護(ITP,Intelligent Tracking Prevention),會偵測有能力跨網站追蹤使用者的網域,並對它們的 Cookie 做分割,或清除其網站資料。WebKit 在 2018 年發表 Storage Access API 的官方公告中指出,一旦嵌入內容被歸類為跨站追蹤者,ITP 就只會給它「分割後的 Cookie」。公告同時提到,WebKit 對這個 API 的初始實作只涵蓋 Cookie,並沒有改變 IndexedDB 或
localStorage的分割方式。 - Firefox 採用的是它稱為狀態分割(State Partitioning)的機制(對外推廣名稱為 Total Cookie Protection)。MDN 記錄了推出的過程:網路分割自 Firefox 85 起對所有使用者預設開啟,動態分割——也就是 Cookie 這一側——則自 Firefox 103 起預設開啟,在此之前曾分階段以自願啟用的方式推出,包括嚴格模式(Firefox 86)與隱私瀏覽(Firefox 90)。
- Chromium 走的是分階段推進的路線。它並不是一個總開關,而是分別對各個部分做分割——先是 HTTP 快取,之後是第三方儲存 API——再搭配一套需要自願啟用的分割式 Cookie 機制,也就是下文介紹的 CHIPS。確切的行為與版本門檻和 Firefox 並不相同,所以請針對你所依賴的 API 查閱瀏覽器相容性資料,別想當然認為各家一致。
對開發者而言,實際的後果是:某個仰賴共用第三方狀態、在一個引擎上能運作的程式碼,在另一個引擎上可能悄悄失效。對使用者而言,實際的後果是:同一個追蹤者,會因為你使用的瀏覽器不同而面對不同的障礙。
分割式 Cookie:CHIPS 與 Partitioned 屬性
直接封鎖第三方 Cookie,會連帶弄壞正當的嵌入內容——一個會針對每個網站記住偏好設定的聊天小工具或地圖,根本沒有追蹤動機,卻會被一刀切的封鎖直接弄壞。CHIPS(Cookies Having Independent Partitioned State,具獨立分割狀態的 Cookie)就是折衷方案:網站透過 Partitioned 屬性,主動讓某個 Cookie 加入分割,瀏覽器便會用雙重索引來儲存它。
Set-Cookie: __Host-widget=abc123; Secure; Path=/; SameSite=None; Partitioned
以這種方式設定的 Cookie,只會在嵌入內容被載入到與設定當時相同的頂層網站底下時,才會被送回。MDN 的 Storage Access API 頁面把這個取捨講得很直白:由於一個無法跟著你跨網站的 Cookie 不會帶來隱私風險,瀏覽器會在請求中送出分割式 Cookie,並讓嵌入的資源可以取用——但也因為這些 Cookie 不會在網站之間共用,它們同樣不會自動在網站之間同步。
最後那一句,就是這套模式的代價。像單一登入頁框這類「登入一次、到處都認得我」的嵌入內容,需要更強的機制。
逃生出口:Storage Access API
Storage Access API讓跨站 iframe 能要求取回它一般的第一方 Cookie。它於 2018 年由 WebKit 率先推出——當時的公告交代了來龍去脈:開發者對 ITP 的回饋是,嵌入內容需要一種方式,來驗證已經登入其第一方服務的使用者。
整個流程有兩個方法:
document.hasStorageAccess()——回傳一個 promise,解析為該頁框目前是否已經擁有未分割的存取權。document.requestStorageAccess()——請求存取權;必須在使用者操作期間呼叫(MDN 稱之為瞬時啟動,transient activation),例如點擊頁框內的「登入」按鈕。
這項授權代表什麼、又不代表什麼:
- 它是針對每一組配對,而不是全域的。 MDN 說明這項權限是以
<top-level site, embedded site>的結構儲存的。嵌在embedder.com裡的example.com所取得的存取權,不會延伸到嵌在其他任何地方的example.com。 - 它恢復的是第一方 Cookie,而不是嵌入者的資料。 WebKit 的文章明確指出,儲存空間存取「絕不會以任何方式放寬同源政策」——這不是第三方伸手進宿主頁面的儲存空間,反過來也不是。
- 各家瀏覽器的詢問方式不同。 根據 MDN,Safari 與 Chrome 會對尚未取得過存取權的嵌入內容跳出詢問,Firefox 則只在某個來源在超過門檻數量的網站上請求存取權之後才會詢問。在 Chrome 中,屬於同一個相關網站集合(related website set)的嵌入內容與嵌入者,可以略過詢問。
- Firefox 也會以啟發式方式授予存取權。 為了避免弄壞常見的整合,它可以在使用者與嵌入內容所開啟的彈出視窗互動之後,或在一連串快速的「導覽—互動—返回」操作之後,給予該嵌入內容 30 天的存取權。MDN 將這些做法標示為過渡性質,並警告開發者不要依賴它們。
這套設計的目標是:取回存取權必須是一個看得見的、針對單一網站、在真實互動情境下所做的決定——而不是追蹤者能夠悄悄一次替所有網站打開的開關。
分割沒有擋住的東西
把界線講精確很重要,因為「已分割」很容易被過度解讀成「有隱私」。
- 第一方追蹤完全不受影響。 網站仍然可以用自己的 Cookie 認出自己的回頭客。分割針對的只是跨站串連。
- 它不影響其他跨站手法。 以其他方式串連造訪紀錄的技術,不在雙重索引的管轄範圍內——例如彈跳追蹤,它讓你短暫經過追蹤者自己的網站,使其以第一方身分執行。偵測你登入了哪些網站也是如此。
- 它不是使用者自選的隔離。 Firefox 的容器是把你自己的各個身分彼此分開;分割則是把每個網站的嵌入內容彼此分開。Firefox 兩者同時採用,誰也無法取代誰——請見容器分頁與追蹤。
- 它不是無痕模式。 隱私視窗會在關閉時丟棄狀態;分割在一般視窗裡同樣適用。至於網站如何仍設法察覺隱私模式,請見無痕偵測。
- 它無法防禦持久性 ID。 對於刻意設計成能撐過清除的識別碼——也就是持久訪客 ID這篇的主題——分割只是移除了其中一條儲存路徑,並沒有移除它的目標。
為什麼這推著追蹤者轉向指紋
以下直接把取捨講明白。分割打斷的是以狀態為基礎的跨站追蹤:追蹤者在一個網站寫進儲存空間的識別碼,再也無法從另一個網站讀出。這一整個家族的技術都仰賴瀏覽器為每個來源維持單一共用儲存空間,而這個前提已經不存在了。
指紋不走這條路。它是根據瀏覽器與硬體本來就會透露的資訊算出來的——canvas 與 WebGL 的輸出、字型、螢幕與硬體數值、音訊行為——不會在你的裝置上寫入任何東西。完全不涉及儲存空間,所以瀏覽器沒有東西可以分割、清除或封鎖。ID 並沒有被存下來;而是下次造訪時,從同樣的輸入再次被辨認出來。
這就是為什麼封住儲存路徑之後,對於任何仍想做跨站串連的人來說,指紋路徑的價值反而升高了。如果你想看看自己的瀏覽器暴露了哪些訊號,我們的瀏覽器指紋識別指南介紹了其運作原理,指紋檢測則能即時顯示結果。
常見問題
儲存空間分割和封鎖第三方 Cookie 是同一回事嗎?
不是。封鎖是在第三方情境中拒絕嵌入內容存取儲存空間。分割則是給它儲存空間——每個頂層網站一個獨立的儲存空間——所以嵌入內容仍能運作,但它在某個網站上儲存的任何東西,在另一個網站上都看不到。
分割會弄壞嵌入式登入與小工具嗎?
可能會。原本仰賴跨許多網站共用同一個 Cookie 來認出已登入使用者的嵌入內容,會在每個網站上發現一個全新、空白的儲存空間。官方支援的修正方式有兩種:使用 Storage Access API 的 requestStorageAccess()(需要使用者操作),或是針對各網站自己的狀態,使用帶有 Partitioned 屬性的 Cookie。
分割會阻止網站在它自己的頁面上追蹤我嗎?
不會。第一方 Cookie 是以你所在的網站作為索引,所以分割不會動到它。分割移除的是透過共用的嵌入儲存空間,在互不相干的網站之間串連你活動紀錄的能力。
所有瀏覽器分割儲存空間的方式都一樣嗎?
不一樣。Safari、Firefox 與 Chromium 推出分割的時間不同、涵蓋範圍也不同,像是涵蓋哪些儲存 API、何時會跳出詢問這類細節也各有差異。在依賴任何一種行為之前,請先查閱該 API 目前的相容性資料。
結語
儲存空間分割是一個小改動,卻帶來很大的影響:把頂層網站加成第二把鑰匙之後,嵌入式追蹤者在某個網站上的儲存空間,和它在另一個網站上的儲存空間,就是兩個完全不同的儲存區。這消除了廉價跨站追蹤所仰賴的共用狀態捷徑,同時替確實需要的正當情境,留下一條受控的回頭路——Storage Access API,或是自願啟用的 Partitioned Cookie。它並沒有消除追蹤;而是把這場較量轉移到完全不需要儲存空間的地方,這也是為什麼一旦你的瀏覽器開始分割狀態,了解指紋只會更重要,而不是更不重要。
推薦閱讀:


