navigator.plugins 不再是真實外掛資料——新版規範已把它寫死。空陣列、多餘項目或與 pdfViewerEnabled 不一致,究竟洩露了什麼?
navigator.plugins 曾經是一份真實清單:使用者裝了哪些 Flash、Java 或 Silverlight 外掛,都會原樣列給任何一個頁面讀取。這份真實清單已經不存在了。新版規範把回傳的清單直接寫死——凡是符合規範的瀏覽器,現在只會回傳同一份固定項目,要嘛全有,要嘛全無。聽起來這個曾經熱門的指紋辨識面已經走到盡頭了。但並非完全如此:一個本該固定的值,一旦不再固定,或者和另一個描述同一能力的 API 對不上,反而變得有資訊量。
核心要點
- 外掛清單不再是真實資料。新版規範把
navigator.plugins寫死:若支援內嵌 PDF 檢視,會回傳恰好五個固定項目;若不支援,則回傳一個空的PluginArray。 navigator.pdfViewerEnabled才是官方認可的判斷方式——MDN 明確說明不要從navigator.plugins推斷這一點。- **這份清單依然帶有一種偵測訊號,只是不再關乎身分識別。**一個自稱是桌面版 Chrome 的瀏覽器回傳空陣列、出現意料之外的多餘項目、或者
navigator.plugins與navigator.pdfViewerEnabled結果矛盾,都屬於內部一致性破綻,而非正常的瀏覽器差異。 - 單獨來看,
navigator.plugins目前的熵值接近於零——幾乎所有真實瀏覽器都只會落在兩種固定狀態之一,所以它已經無法像 canvas 或字型指紋那樣區分不同訪客。它剩下的價值,是疊加在其它訊號之上的一致性檢查,而不是獨立的身分識別手段。 - **這與瀏覽器擴充功能是完全不同的偵測面。**擴充功能是使用者自行安裝的附加元件,靠另一套完全不同的方式偵測;
navigator.plugins描述的始終只是瀏覽器自身內建的外掛/PDF 處理層。
navigator.plugins 現在到底回傳什麼
呼叫 navigator.plugins 仍然會得到一個 PluginArray——它不是真正的 JavaScript 陣列,而是一個具有 length、item(index)、namedItem(name) 的類陣列物件。但裡面的內容已經不再是從作業系統裡探測出來的了。按照目前規範,內容只會是以下兩種固定結果之一:
- 若瀏覽器支援內嵌 PDF 檢視,陣列會包含五個具體項目:
"PDF Viewer"、"Chrome PDF Viewer"、"Chromium PDF Viewer"、"Microsoft Edge PDF Viewer"、"WebKit built-in PDF"。 - 若不支援,陣列為空。
if ("PDF Viewer" in navigator.plugins) {
// 瀏覽器支援內嵌檢視 PDF 檔案。
}
僅此而已。不存在第三種狀態,不會回傳部分清單,一個符合規範的真實瀏覽器也不可能報出三個外掛或叫別的名字的外掛。MDN 已把 PluginArray 標記為棄用——屬於未來的移除候選——而且它自身的屬性在目前瀏覽器版本中已不再可列舉,這堵住了過去用 for...in 迴圈遍歷陣列的老套路。
navigator.mimeTypes 經歷了一模一樣的變化。它回傳一個 MimeTypeArray,按規範在支援內嵌 PDF 檢視時包含 application/pdf 與 text/pdf 兩個項目,否則回傳空清單——寫死的方式一樣,綁定的也是同一個底層能力位元。
navigator.pdfViewerEnabled 才是替代方案——不是 navigator.plugins
正因為外掛清單已經收縮為一個關於 PDF 支援的單一是非訊號,平台新增了一個直接給出答案的屬性:navigator.pdfViewerEnabled,一個純粹的布林值。MDN 在 plugins 和 mimeTypes 兩個頁面都明確寫出了這個遷移方向:要判斷是否支援內嵌檢視 PDF 檔案,請使用 navigator.pdfViewerEnabled,不要從這兩個舊屬性去推斷。
這條說明正是 navigator.plugins 依然值得深入討論的原因。想知道「這個瀏覽器能不能內嵌顯示 PDF」的正規程式碼,現在有了官方認可的直接答案。而仍然靠 navigator.plugins.length 或者按名字尋找 "PDF Viewer" 來分支判斷的程式碼,要嘛是舊程式碼,要嘛就是在做與 PDF 支援無關的別的事——而這恰恰是偵測方最想刻畫的那種程式碼。
為什麼一份寫死的清單依然是偵測訊號
一個只有兩種合法狀態的值本身無法識別訪客——但它可以抓出一個不符合自身聲稱身分的瀏覽器環境。這就是它剩下的全部用途,而且完全落在內部一致性上,而不是唯一性上:
**該有完整清單的地方出現空陣列。**一個自稱是現代桌面版 Chrome 的 User-Agent 字串,按規範應當回傳那五條 PDF 檢視器清單——因為近期的 Chrome 預設開啟內嵌 PDF 檢視。在這樣一個聲稱的組態下,navigator.plugins 卻是空的,這是一處值得關注的錯位,也正是無頭與自動化瀏覽器環境歷來容易露出的破綻之一,有時是因為自動化框架直接把 PDF 檢視器元件整個停用了。
**項目與固定集合對不上。**由於規範把五個外掛名稱寫死,任何超出這個集合的外掛項目——一個陌生的名字、不同的數量、一個本該是字串卻顯示成 [object Object] 的項目——都說明這個屬性被指令碼修補過,而不是瀏覽器原生產生的。諷刺的是,那些試圖偽造一份「看起來真實」的外掛清單的反偵測工具,恰恰最容易產生一份與真實、最新瀏覽器實際輸出對不上的清單。而且這種修補通常還會留下第二處痕跡:用普通物件或 JavaScript 陣列把這個屬性換掉之後,原生 navigator.plugins 能通過的那幾項檢查就過不去了——原生物件的原型仍然是 PluginArray,String(navigator.plugins) 仍然是 "[object PluginArray]",它的方法轉成字串後也仍然是原生程式碼。
**navigator.plugins 與 navigator.pdfViewerEnabled 結果矛盾。**這兩個屬性描述的是同一個底層能力,只是來自規範的兩個不同時期。在真實、未被修改的瀏覽器裡,它們始終一致:非空的外掛清單意味著 pdfViewerEnabled === true,反之亦然。一個同時查詢這兩者、發現它們互相矛盾的頁面——比如 pdfViewerEnabled 為真而 navigator.plugins 卻是空的,或者反過來——抓到的就是指令碼只改了它知道的那個屬性——偽造程式碼常常只盯著自己熟悉的舊屬性,忘了還有一個更新的屬性存在。
以上這些偵測都無法說出訪客是誰。它們說明這個環境在內部對不上號——而這正是自動化和偽造瀏覽器畫像比真實瀏覽器更常留下的破綻。
與瀏覽器擴充功能不是同一個面
很容易把「外掛」和「擴充功能」混為一談,因為兩者歷史上都算瀏覽器的附加元件,但偵測方式和意義完全不同。navigator.plugins 描述的是瀏覽器自身內建的外掛與 PDF 處理架構,如今已經收縮成那一個寫死的 PDF 訊號。瀏覽器擴充功能(uBlock Origin、密碼管理員、廣告攔截器)則是使用者自行安裝的軟體,頁面根本無法透過這個 API 列舉它們——偵測已安裝擴充功能要靠別的技術,例如探測某個擴充功能自身可公開存取的資源是否有回應。如果你更關心頁面能從使用者安裝的擴充功能裡探到什麼,而不是瀏覽器內建的這個外掛旗標,可以看我們關於瀏覽器擴充功能隱私風險的文章。
熵值現實檢查
有必要直白地說清楚:navigator.plugins 單獨來看,如今對指紋的貢獻微乎其微。在所有符合規範的瀏覽器裡只有兩種合法狀態,它幾乎不再增加任何區分度——完全無法和 canvas 算繪、已安裝字型、WebGL 參數這些訊號相比。一些舊的瀏覽器指紋科普文章依然把 navigator.plugins 描述成一個資訊量豐富的逐使用者訊號,那是在寫死改動之前成立的說法;今天再這麼看就高估了它的作用。它現在真正有用的地方變窄了、也變了性質:不是「這是誰」,而是「這個環境關於 PDF 支援的各項訊號,彼此之間、與它自稱的身分之間,是否對得上」。這一點和 Permissions API 狀態指紋屬於同一類——同樣是無需跳出視窗、無需點擊的讀取,用作一致性檢查比用作原始熵值來源更有價值。相比之下,它也遠不如 enumerateDevices() 暴露的攝影機、麥克風清單那樣,真的能區分不同裝置。想了解哪些訊號如今依然貢獻真實的區分度,可以參考我們的瀏覽器指紋辨識完全指南。
檢測你自己的瀏覽器
用 BrowserInsight 的外掛檢測工具,你可以直接看到自己瀏覽器在這個屬性上的真實回傳值——具體項目、數量,以及 PDF 檢視器是否啟用。一致性那一面它也一併跑了:外掛清單與 navigator.mimeTypes 是否吻合、PluginArray 物件看起來是否仍是原生而非被修補過,再加上接在 navigator.plugins 之後的擴充功能偵測。如果想把這一個屬性放進 canvas、WebGL、字型等全部訊號的整體畫面裡看,可以用指紋檢測。
常見問題
現代瀏覽器裡 navigator.plugins 為空正常嗎?
正常。空陣列只是說明瀏覽器在預設組態下不支援內嵌 PDF 檢視——這是一個合法、符合規範的狀態,本身並不代表被竄改過。它只有和其它訊號放在一起時才有意義,例如某個 User-Agent 自稱是理應支援內嵌 PDF 的瀏覽器版本。
我還能用 navigator.plugins 來判斷是否支援 PDF 嗎?
技術上可以,但不建議——MDN 明確建議改用 navigator.pdfViewerEnabled 來做這個判斷。navigator.plugins 和 navigator.mimeTypes 都已被列為未來可能移除的候選。
為什麼機器人的 navigator.plugins 清單會看起來不對?
因為真實、符合規範的清單只有兩種可能的形態,任何試圖注入一份「看起來真實」的自訂外掛清單來偽裝成人類的指令碼,本質上都是在對抗一個已經固定的目標:偵測方早就知道真清單長什麼樣,凡是對不上的一眼就能看出來。手工拼出來的外掛清單更可能洩露自動化,而不是掩蓋它——尤其是當它和 navigator.pdfViewerEnabled 對不上,或者被換掉後的物件已經不像一個原生 PluginArray 的時候。
navigator.plugins 對指紋辨識還有意義嗎?
意義很小,而且和過去完全不同了。它單獨貢獻的熵值幾乎為零。它剩下的價值,是作為 navigator.pdfViewerEnabled 與瀏覽器聲稱身分之間的一致性檢查,而不是用來區分兩個訪客。


