WebRTC 指紋讀取你的編解碼器清單與 SDP 提議,而非你的 IP。了解其原理、與 WebRTC 洩漏的差異,以及如何降低它。
WebRTC 指紋技術透過讀取瀏覽器支援的音訊/視訊編解碼器清單,以及它在協商通話時產生的 SDP(會話描述協定)文字的確切結構來識別你的瀏覽器——完全不會碰觸你的 IP 位址。指令碼只需呼叫一個靜態方法,就能取得一份結構化的編解碼器與標頭擴充清單,並利用這份清單的樣貌來協助區分瀏覽器、引擎與平台。這與廣為人知的 WebRTC IP 洩漏 是完全不同的機制,把兩者混為一談會帶來一種虛假的安全感:解決了其中一個,對另一個毫無幫助。
重點摘要
- WebRTC 指紋技術讀取的是編解碼器支援情況與 SDP 結構——它從不碰觸你的公網或本機 IP 位址,因此與經典的 WebRTC 洩漏毫無關係。
- 核心訊號來自
RTCRtpSender.getCapabilities(),這是一個靜態方法,無需任何權限彈窗、也不產生任何網路流量即可回傳你支援的編解碼器。 createOffer()產生的 SDP 文字又增添了一層訊號:負載類型編號、編解碼器排列順序,以及像profile-level-id或packetization-mode這類逐編解碼器參數。- 單看這個訊號相當粗略——它主要區分的是瀏覽器引擎、版本與平台,而非唯一識別某一個人——但它會作為疊加層,與 Canvas、WebGL 及音訊指紋一起發揮作用。
- 徹底停用 WebRTC 能移除這個暴露面;隨著時間推移,讓數值改變的主要是瀏覽器更新,以及作業系統層級的硬體編解碼支援。
什麼是 WebRTC 指紋技術?
每個實作了 WebRTC 的瀏覽器都會攜帶一組特定的音訊與視訊編解碼器,按特定順序排列,並帶有特定參數。基於 Chromium 的瀏覽器、Firefox 與 Safari 各自建構在不同的底層媒體堆疊之上,因此確切的編解碼器清單——以及某個作業系統上哪些編解碼器能取得硬體加速——在它們之間各不相同。指令碼可以直接讀取這份清單,或促使瀏覽器產生一份 SDP 提議,並將其中任一者當作裝置/瀏覽器訊號使用。
關鍵在於,這與 WebRTC IP 洩漏 並非同一類風險——在 IP 洩漏中,ICE/STUN 流程可能在你使用 VPN 時仍暴露你的真實公網 IP。而編解碼器與 SDP 指紋揭露的是你的瀏覽器是什麼,而不是你身在何處。你完全可能做到零 WebRTC 洩漏(一套設定完善、全程走代理的 VPN),卻依然暴露出一份再普通不過的編解碼器指紋,反之亦然。
無需建立連線即可讀取編解碼器能力
最簡單、最不動聲色的技術甚至不需要建立一個 peer connection。RTCRtpSender.getCapabilities(kind) 是一個靜態方法——它會立即回傳瀏覽器支援的編解碼器與標頭擴充,沒有權限彈窗、沒有信令,也沒有任何網路活動:
function getWebRTCCodecFingerprint() {
if (!window.RTCRtpSender || !RTCRtpSender.getCapabilities) {
return { supported: false };
}
const audio = RTCRtpSender.getCapabilities('audio');
const video = RTCRtpSender.getCapabilities('video');
return {
supported: true,
audioCodecs: audio.codecs.map((c) => c.mimeType),
videoCodecs: video.codecs.map(
(c) => `${c.mimeType}${c.sdpFmtpLine ? ' ' + c.sdpFmtpLine : ''}`
),
headerExtensions: video.headerExtensions.map((h) => h.uri),
};
}
回傳的 codecs 陣列包含每個編解碼器的 MIME 類型、時脈頻率、聲道數,以及一個可選的 sdpFmtpLine,其中帶有編解碼器專屬的參數。headerExtensions 陣列則列出受支援的 RTP 標頭擴充(用於音量等級、傳輸層級壅塞控制等用途),它們的有無與排列順序同樣會因引擎與版本而異。
SDP 提議中包含什麼
如果指令碼更進一步,實際呼叫了 createOffer(),產生的 SDP 文字會以更細緻的形式暴露同樣的資訊:負載類型編號、編解碼器排序,以及逐編解碼器的屬性行。以下是一段經過精簡、僅供示意的視訊區段:
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 102 127
a=rtpmap:96 VP8/90000
a=rtpmap:98 VP9/90000
a=rtpmap:102 H264/90000
a=fmtp:102 profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1
a=rtpmap:127 AV1/90000
SDP 格式本身是一份標準化的 IETF 文字協定——真正有趣的指紋訊號並非語法本身,而是你這台特定瀏覽器/系統/版本所選擇呈現的負載類型編號、編解碼器順序與 fmtp 參數的具體組合。不同平台上的兩個瀏覽器,很少會完全重現同一種組合。
這與 WebRTC IP 洩漏有何不同
有必要把這條界線說清楚,因為這兩種技術共用同一套程式碼庫(WebRTC),但除此之外沒有任何共通點:
| WebRTC IP 洩漏 | WebRTC 編解碼器/SDP 指紋 | |
|---|---|---|
| 暴露了什麼 | 你的真實公網/本機 IP 位址 | 你的瀏覽器引擎、版本與平台 |
| 機制 | 透過 STUN/TURN 進行 ICE 候選者收集 | getCapabilities() 和/或 SDP 提議內容 |
| 是否需要網路往返? | 是——需要與 STUN 伺服器通訊 | 否——getCapabilities() 完全在本機完成 |
| 會繞過 VPN 嗎? | 若路由在通道之外洩漏,則可能 | 不適用——不涉及任何位置資料 |
| 修復方式 | 限制/停用 WebRTC,或改用不洩漏的 VPN | 停用 WebRTC,或減少編解碼器暴露面 |
如果你已經堵住了 WebRTC 洩漏,那保護的是你的所在位置——它對編解碼器/SDP 訊號毫無作用,因為 getCapabilities() 從一開始就不會請求任何網路存取權限。
這個訊號的區分度有多高?
編解碼器與 SDP 指紋相對而言是一種較為粗略的訊號。由於 Chrome、Edge、Opera 與 Brave 都建構在同一套 Chromium/libwebrtc 基礎之上,它們回報的編解碼器清單往往非常相似——這個訊號主要區分的是引擎家族(Chromium vs. Gecko vs. WebKit)與平台(作業系統向瀏覽器暴露了哪些硬體解碼器),而非精確鎖定某一個具體的人。
| 因素 | 揭露了什麼 |
|---|---|
| 編解碼器清單與順序 | 算繪引擎家族與版本 |
sdpFmtpLine 參數(如 H.264 的 profile-level-id) | 平台媒體堆疊與硬體解碼器支援 |
| 標頭擴充清單 | 引擎版本,有時也包含已啟用的實驗性功能 |
| 是否支援 AV1/HEVC | 作業系統與硬體加速能力 |
這使它只能算是一個適度的貢獻者——就像 音訊指紋 一樣:單靠它不足以識別出你,但它是另一個獨立的位元貢獻者,會與 Canvas 及 WebGL 訊號疊加,進一步縮小人群範圍。
編解碼器之外的媒體能力
還有一個值得認識的相關但獨立的 API:媒體能力 API(Media Capabilities API),具體來說是 navigator.mediaCapabilities.decodingInfo()。它並不屬於 WebRTC 的一部分,但常與 WebRTC 一起被探測,因為它回答的是類似的問題——這台裝置的媒體管線究竟能做什麼——具體做法是回報解碼某個編解碼器/解析度/畫格率組合是否會是 smooth(流暢)與 powerEfficient(省電,即取得硬體加速)。由於硬體加速支援與具體的 GPU 及作業系統媒體框架綁定,這在 WebRTC 暴露的軟體編解碼器清單之上,又疊加了一層帶有硬體色彩的訊號。
防護手段及其取捨
| 做法 | 效果 | 取捨 |
|---|---|---|
停用 WebRTC(Firefox 的 media.peerconnection.enabled) | 同時移除編解碼器/SDP 訊號與 IP 洩漏暴露面 | 會徹底破壞瀏覽器內的視訊/語音通話 |
| Tor 瀏覽器 | 預設停用 WebRTC | 同樣會失去這部分功能,但在所有 Tor 使用者之間保持一致 |
| 透過擴充功能限制為單一編解碼器組合 | 可減少回報的編解碼器 | 少有主流擴充功能專門針對此訊號,多數擴充功能關注的是 IP 洩漏 |
| 接受這個訊號,把心力放在別處 | 不會損失任何功能 | 對多數威脅模型而言,相較於 Canvas/WebGL,編解碼器指紋是價值較低的目標 |
目前並沒有一個像 Canvas 或音訊「farbling」那樣、專門用來「隨機化我的編解碼器清單」的主流開關,主要是因為這個訊號本身就比那些訊號更粗略、價值更低。對多數人來說,實際的做法是把它當作疊加在高熵訊號之上的又一項輸入,而不是單獨為它較勁的戰場。
如何檢查你自己的訊號
無需撰寫任何程式碼,你就能看到自己的瀏覽器暴露了什麼:
- 執行 BrowserInsight 的 指紋檢測,查看你的綜合指紋樣貌,包括像這類低熵訊號在你整體獨特性中所佔的比重。
- 開啟瀏覽器的開發者主控台,執行上面的
getWebRTCCodecFingerprint()程式碼片段,查看你的原始編解碼器清單。 - 在同一台機器上,把這個測試分別放到 Chrome、Firefox 與 Safari 中執行比較——即使硬體完全相同,不同引擎之間的編解碼器順序與
fmtp參數通常也會有所差異。EFF 的 Cover Your Tracks 專案也是一個很好的輔助檢測,能看看你整體的設定與他人相比如何。
常見問題
WebRTC 指紋會暴露我的 IP 位址嗎?
不會。編解碼器與 SDP 指紋讀取的是你的瀏覽器支援什麼,使用的是 RTCRtpSender.getCapabilities() 或 SDP 提議的內容——兩者都不涉及你的網路位址。IP 暴露是一種獨立的機制(即 WebRTC 洩漏),在我們的 WebRTC 洩漏防護指南 中有介紹。
停用 WebRTC 能同時解決洩漏與指紋問題嗎?
可以——徹底停用 WebRTC(或使用像 Tor 這種預設停用它的瀏覽器),能一次性移除這兩個暴露面,因為無論是 getCapabilities() 還是 SDP 協商,在 WebRTC 未啟用的情況下都無法運作。代價是瀏覽器內的視訊/語音通話功能會隨之失效。
編解碼器指紋和 Canvas 或 WebGL 指紋一樣具有識別性嗎?
不,它通常較弱。由於主流的 Chromium 基礎瀏覽器共用同一套底層 libwebrtc 技術堆疊,它們的編解碼器清單看起來很相似,因此這個訊號主要揭露的是引擎家族與平台,而非精確鎖定某個個體。它仍會為整體的熵值疊加做出貢獻,只是不如算繪類訊號那麼多。
網站能在未經許可的情況下讀取我的編解碼器清單嗎?
可以。RTCRtpSender.getCapabilities() 是一個靜態方法,執行時不會跳出攝影機/麥克風權限提示,也不會發出任何網路請求——它只是單純回報瀏覽器的 WebRTC 實作所支援的內容。
總結
WebRTC 指紋技術與 WebRTC IP 洩漏都寄居於同一個 API 之內,但它們暴露的是完全不同的東西:一個揭露你真實的網路位址,另一個則透過編解碼器支援與 SDP 結構揭露你的瀏覽器引擎、版本與平台。兩者互不能替代。單獨來看,編解碼器/SDP 指紋只是一個適度、粗粒度的訊號——但理解它意味著你不會把一套堵住洩漏的 VPN 設定,誤當成一套對指紋也免疫的設定。
推薦閱讀:


