LinkedIn 的 BrowserGate,以及為什麼「一個瀏覽器身分」已經不夠用
LinkedIn 每次造訪都悄悄探測超過 6,000 個瀏覽器擴充功能、蒐集 48 項裝置屬性,並透過 WebRTC 抓取你的 LAN IP。修補這件事的,不是某個隱私設定——而是一種形狀截然不同的瀏覽器。
每次你打開 LinkedIn,那個頁面都會悄悄向你的瀏覽器丟出好幾千個問題——哪些擴充功能裝好了、哪些字型、哪顆 GPU、CPU 核心有幾個、本機 IP 位址是什麼。然後它把答案寫進一個標頭,掛在接下來每一個請求上。你沒有同意這件事,你也看不到它發生。這不是 bug;它的代號叫「Spectroscopy」。
在四月初,一個歐洲 LinkedIn 使用者團體 Fairlinked e.V. 公布了一份調查報告。看你怎麼算,它要嘛是這個十年裡最詳細的瀏覽器指紋追蹤故事,要嘛是最不令人意外的那個。他們展示,LinkedIn 自家的前端 JavaScript,每次你載入這個網站,都會對 chrome-extension:// 形式的網址發射六千到七千次 fetch() 請求,測試每一個是否能解析,另外再蒐集 48 項裝置與瀏覽器特徵,然後把整包資料——以 RSA 加密、掛在之後每一個 API 請求上——回傳到 LinkedIn 的遙測端點。
這則報導被 The Next Web 接手,404 Privacy 獨立驗證,另外還有一篇長篇的技術拆解,在程式碼層級對實際 payload 逐行做了逆向工程。Fairlinked 的姊妹組織 Teamfluence Signal Systems,早在 2026 年 1 月就已經依據歐盟的 Digital Markets Act(DMA,規範守門人平台必須如何對待使用者的歐洲法規)於慕尼黑聲請了假處分。法院駁回。LinkedIn 則對媒體回應,這些指控「完全錯誤」,並稱其掃描僅針對違反服務條款的擴充功能。
這篇文章不打算討論 LinkedIn 在愛爾蘭或德國是否站得住腳。它要討論的,是這個故事所揭示的事:你現在正在讀這篇文章的瀏覽器,從未被設計成能頂住這類行為,而且——更要緊地——根本無法頂住,因為它只有「一個身分」可以給。
當你造訪 linkedin.com 時,頁面實際在做什麼
有兩套機制並行運作,就算你從來沒打開過 DevTools 面板,還是值得搞懂它們。
主動擴充功能偵測。 這個頁面硬編碼了一份超過 6,000 組的 Chrome 擴充功能 ID 清單。對每一個 ID,它會對擴充功能封裝中的某個已知檔案發動 fetch()——比方說 chrome-extension://<id>/manifest.json,或是某個特定的 icon。如果 fetch 成功,那個擴充功能就是已安裝的;如果 Chrome 拒絕這個請求,那就沒裝。這個小把戲只對至少開放一項「web-accessible resource」的擴充功能有效,而大多數真正的擴充功能都會開放。文章中指出還有一種隱身變體會使用 window.requestIdleCallback() 搭配交錯延遲,避免把網路面板點亮。
被動 DOM 掃描(「Spectroscopy」)。 另外,頁面會在你的 DOM 上走一遍,搜尋 chrome-extension:// 形式的網址引用。這個方法可以抓到會把內容注入頁面的擴充功能——也就是那份硬編碼清單可能漏掉的,或者清單還沒學到的新擴充功能。
這些結果會餵進一條 LinkedIn 內部稱為 APFC 的指紋追蹤流水線,全名「Anti-fraud Platform Features Collection」,另外還有一個叫 DNA 的別名,意思是「Device Network Analysis」。除了擴充功能清單之外,這條流水線還蒐集:
Canvas 指紋
頁面用指定的文字、曲線和顏色畫一張隱藏的圖片,然後讀回像素值。確切的像素數值取決於你的 GPU 驅動程式、字型光柵化器和 OS 版本——足以產生一個跨頁面載入都穩定、而且罕見到足以在回訪時把你認出來的簽章。
WebGL 渲染器
超過 65 個描述你圖形堆疊的參數:廠商字串、驅動程式版本、支援的擴充、著色器精度。同一套 OS 上的筆電與桌機,會產生不同的 WebGL 簽章。
音訊脈絡
透過瀏覽器的 oscillator 與 compressor 節點跑一段無聲音訊,所導出的一組指紋。不同的音訊堆疊對浮點數運算的捨入方式會有微妙差異。
WebRTC 本機 IP
WebRTC 是瀏覽器的即時通話 API。它在探索網路路徑時會產生一個內建副作用:可以被要求交出你的 LAN IP 位址——也就是路由器配給你的 192.168.x 或 10.x 那個數字——即使你在 VPN 後面也一樣。LinkedIn 就是這樣問。
硬體與語系
CPU 核心數、裝置記憶體、螢幕解析度與像素比、時區、語言、電池剩餘量與放電時間、已安裝字型、觸控支援。根據 Fairlinked 的報告,總共 48 項屬性。
再加上擴充功能清單
上述那個上千筆的大規模探測。大多數指紋追蹤論文會把「已安裝擴充功能」當成錦上添花的訊號;LinkedIn 則把它當成頭牌訊號。
這些訊號會被合成一個加密後的資料塊,以 HTTP 標頭的形式掛在該頁面發出的每一個後續 API 請求上——如此一來,LinkedIn 後端在每一次請求中都能精準知道你是哪一台裝置。這份調查也指出,LinkedIn 已經對那些使用它不喜歡之擴充功能的使用者採取過行動——停權、警告——這是這份資料確實被「使用」而不只是「蒐集」的最直接證據。
在這個法律問題底下,還有一個更真實的問題:如果 LinkedIn 是在這種規模下做這件事,那有多少其他網站也在做縮小版?老實說:多數大站都有。LinkedIn 之所以特別,僅僅在於它擴充功能清單的廣度,以及它工程細節上的用心。消費性網路其他地方跑的,是同一套基本劇本,只是精緻程度不同而已。
問題不是指紋追蹤。問題是身分被重複使用。
退一步看。Canvas、WebGL、WebRTC、字型列舉——這些都不是新玩意兒。過去十年每一位資安研究員都寫過一篇結尾是「把 Firefox 的 resistFingerprinting 打開」或「裝 CanvasBlocker」的短文。這些建議嚴格說來沒有錯,但它沒打到這個問題的承重牆。
就算你擁有完美的反指紋抗性——每一個訊號都被標準化、每一張 canvas 都一片空白、每一次 WebRTC 連線都被拒絕——你的瀏覽器仍然只有一個 cookie jar、一個歷史紀錄檔、一組登入的工作階段、一個儲存密碼的金庫、一份已安裝擴充功能清單、在網路層一個 IP 位址。你在網路上做的每一件事,都從這一個身分流出去。就算指紋追蹤者讀不到你的 canvas,他仍然分得出來:登入 LinkedIn 的那個人、登入 Facebook 的那個人、逛獨立小書店的那個人,還有查健保入口網站的那個人,全都來自同一個瀏覽器實例、同一組 cookies、同一個 IP。而這個網路效應是跨站的:LinkedIn 的資料,一旦能和其他站點接在一起,價值就會躍升。
這就是為什麼「一個孤立的反指紋擴充功能」並不能真正解決問題,也是為什麼「在普通瀏覽器上加一個 VPN」一樣解決不了。VPN 會換掉你看起來的 IP,卻不會把你的瀏覽器切成多個身分。你仍然只有一個 cookie jar。你仍然只有一組工作階段。LinkedIn 和 Facebook 仍然看到同一台機器——而且現在,對他們有用地,是一台能和某個 VPN 的 IP 歷史對得上的機器。
以分頁為單位的 VPN 論點
故事從這裡開始變得不一樣。因為每個 Bromure 分頁都是它自己的、用完即丟的 Linux 虛擬機,所以 VPN 是屬於那個「分頁」的,而不是整個瀏覽器的,也不是整台電腦的。就是那個分頁。
你可以把一個瑞典的 Mullvad 端點接到你的 LinkedIn 設定檔,把一個瑞士的 ProtonVPN 端點接到你的 Facebook 設定檔,把 Cloudflare WARP 接到一個「雜七雜八連結」的設定檔,然後讓你的本地銀行設定檔完全不接任何 VPN——全都同時發生,在同一台 Mac 上、同一個 Bromure 應用程式裡。LinkedIn 看到的是瑞典出口。Facebook 看到的是瑞士出口。銀行看到的是你家真正的網路連線。沒有一個網站有什麼乾淨的方式能發現:他們其實看的是同一個人的筆電。
這不是紙上談兵式的隔離。Bromure 透過 Apple's Virtualization.framework,為每個分頁啟動一個真正的 Linux 核心。每個 VM 有自己的核心網路堆疊、自己的 /etc/hosts、自己的行程樹、自己的一組 Chromium flags、位在自己虛擬磁碟上的自己的設定檔目錄。兩個分頁打開兩個會做指紋追蹤的網站、由兩個不同的 VPN 端點連出去,在指紋追蹤運作的那一層看來,和兩個人各自用兩台筆電無從區分,因為在那一層,他們就是。
以分頁為單位的 VPN 設定,位在設定檔的 VPN 與廣告 面板,總共有三個選項:Cloudflare WARP(Cloudflare 的消費級加密服務)、WireGuard(任何供應商、任何自架伺服器——貼入一份 .conf 即可),或 IKEv2(給公司 VPN 用)。VPN 是在 VM 裡面跑的,也就是說,就連客體的 Chromium 行程都看不到你真正的 IP。
Bromure 預設關閉 WebRTC
WebRTC 是 BrowserGate 中 LAN-IP 外洩的直接元兇。它當初是為瀏覽器對瀏覽器的影音通話設計的,而在它探索網路路徑的過程中,產生了一個副作用:可以被要求列舉你的本地網路介面。任何網站——不只你正在和它通話的那個——都能在背景跑這份列舉,得到類似「這位使用者的路由器給了他 192.168.1.47,所以他在典型家用網路,而且範圍和這個指紋上次造訪時一樣」這類資訊。
Bromure 對於任何沒有同時啟用網路攝影機與麥克風的設定檔,預設把 WebRTC 關掉。具體來說:當設定檔不需要網路攝影機或麥克風存取時,Bromure 啟動器會加上兩個 Chromium flags:
--force-webrtc-ip-handling-policy=disable_non_proxied_udp--enforce-webrtc-ip-permission-check
並載入一個叫做 webrtc-block 的小擴充功能,把 RTCPeerConnection 這個建構式替換成一個什麼都不做的樁(no-op stub)。最後這一步很重要:光靠那個 policy flag 可以擋住 IP 透過 UDP 外洩,但有心的指紋追蹤者還是可以實例化一個 RTCPeerConnection 去觀察行為;這個樁則連建構式本身都會失敗。總效果是:一個在 Bromure 上、不需要 WebRTC 的設定檔,碰到試圖複製 LinkedIn 那套 LAN-IP 伎倆的網站,拿回來的是一個空空的結果。
你完全不需要為此動任何開關。只要設定檔裡沒啟用影音通話硬體,這就是預設狀態。如果你在某個設定檔的 媒體 面板裡打開了網路攝影機或麥克風分享,那些需要 WebRTC 的 VPN 與影音通話情境會自動回來。這個設定的原則是「只有在你真的需要時才開」,也比較貼近網路原本應該要運作的方式。
隔離不能解決的事
有兩件事值得先講清楚。第一,如果你在每個設定檔裡都用真名登入 LinkedIn,LinkedIn 還是知道那是你。隔離並不能讓你對自願登入的服務匿名;它切斷的是跨站的身分拼接,以及工作階段之間的被動再識別。這些都是實實在在的收穫,但不是匿名性。
第二,Bromure 無法阻止 LinkedIn 在 Bromure 的 VM 裡面跑它的擴充功能掃描。但它能——也確實——讓那份掃描結果變得沒用:預設情況下,Bromure 的設定檔除了它自己內部那些擴充功能之外不裝任何 Chrome 擴充功能,而那些內部擴充功能用的是與設定檔綁定的擴充功能 ID,不在 LinkedIn 的硬編碼清單裡。頁面盡責地探測了 6,000 個 ID;什麼都沒回來。那份 48 項屬性的指紋仍然會被蒐集——但它識別到的是一個用完即丟的 VM,而這個 VM 的 WebRTC、cookies 與 IP 都不和你跑的其他 VM 重疊。
這已經足以讓 BrowserGate 失去它作為跨站關聯工具的毒牙。但它並不足以在你登入後把你藏起來不讓 LinkedIn 看見,我們也不會假裝它可以。
針對 LinkedIn(與類似網站)建議的 Bromure 設定
如果你要設定一個專門給 LinkedIn 用的設定檔,或給 Facebook 的,或任何以激進指紋追蹤聞名的社群平台,這些是值得勾選的預設值。下面每一項都在單一設定檔的設定面板裡(清單上設定檔旁邊的齒輪圖示)。
一般 → 保留瀏覽資料:開啟
預設情況下,Bromure 會在你關閉視窗時銷毀一切,這對於隨手瀏覽是對的,但對於你每天要登入的網站就錯了。打開這個選項,cookies 和密碼會保留在一個專屬的虛擬磁碟上,跨工作階段存活。你不必每次都重登。
隱私與安全 → AI 網路釣魚偵測:開啟
LinkedIn 上的網路釣魚——假冒獵頭訊息、連到帳密收集頁——是很大一類。AI 網路釣魚偵測會把當前頁面的網址、可見文字與表單結構送到 Bromure 的分析伺服器評分,在你往假表單裡輸入資料之前先提醒你。當這項功能開啟時,資料會離開本地 VM,這件事值得你知道。
媒體 → 分享網路攝影機:關閉
LinkedIn 不需要你的鏡頭。把網路攝影機關掉,WebRTC 也會跟著被停用,而這正是 Fairlinked 調查所記錄的本機 IP 外洩的直接對策。
媒體 → 分享麥克風:關閉
同樣的理由。網路攝影機和麥克風兩個都必須關掉,自動 WebRTC 終止開關才會啟動(WebRTC 是這兩者共同依賴的 API)。
檔案傳輸 → 檔案下載:關閉
正常使用 LinkedIn 不需要從 LinkedIn 下載檔案。把下載關掉,意味著就算你不小心點到不該點的東西,一個被攻陷的頁面也無法把任何東西丟到你的 Mac 上。如果你需要以履歷表投遞職缺,檔案上傳可以保持開啟。
VPN 與廣告 → WireGuard(或 WARP):開啟
這就是「以分頁為單位的 VPN」的實際落地。貼上一份你想讓 LinkedIn 看到的出口節點的 WireGuard 設定(Mullvad、ProtonVPN,或是一台自架伺服器),打開 啟動時連線,之後 LinkedIn 看到的 IP,和你其他分頁完全不一樣。如果你還沒有 WireGuard 供應商,WARP 是比較簡單的一鍵選項。
有幾個不那麼明顯的小註解。只要網路攝影機與麥克風都關閉,這個設定檔的 WebRTC 已經是關的——你不需要在任何地方設定,也沒有獨立的核取方塊,因為它是從那兩個設定推導出來的。
如果你為了工作需要,跑一個專門的 LinkedIn 設定檔,並希望 VPN 工作階段能撐過單一分頁被關閉,那就把 保留瀏覽資料 和 WireGuard 底下的 啟動時連線 一起打開——每次你重新打開那個設定檔,VPN 就會自動連上。
你也可以再往前一步。進階 面板裡有一個 加密瀏覽資料 選項,它會用 LUKS 加密那份持久磁碟,金鑰則存在 macOS Keychain 裡。對於那些社群媒體相鄰、但你又希望能跨重開機保留的東西,這是一個合理的偏執等級。
修補的輪廓
BrowserGate 是一個好的象徵,它代表著已經存在一陣子、而且正在惡化的事實:普通瀏覽器無法對這一類監控形成有意義的抵抗,因為它們整個架構都圍繞著「每個瀏覽器實例一個身分」設計的。你可以裝一些擴充功能去緩解特定的外洩,而且你也該這麼做;但結構性的答案,是一個每個分頁都是自己一台電腦的瀏覽器,有自己的網路、自己的隱私面,以及自己的「結束」能力。關上視窗,那個身分——不管 LinkedIn 的掃描器蒐集了什麼、附帶了什麼關聯 cookies——就不見了。
這就是修補的整個形狀。它不取決於 LinkedIn 答應停手,也不取決於 DMA。它取決於你的瀏覽器,長成和你當初買這台筆電時內建的那個,截然不同的形狀。