navigator.plugins không còn là dữ liệu plugin thật - đặc tả mới đã cố định nó. Mảng rỗng, mục thừa, hay lệch với pdfViewerEnabled tiết lộ điều gì?
navigator.plugins từng là một danh sách thật: bất kỳ plugin Flash, Java hay Silverlight nào người dùng đã cài, đều được liệt kê nguyên trạng cho bất kỳ trang nào đọc. Danh sách thật đó không còn nữa. Các phiên bản đặc tả gần đây cố định cứng danh sách trả về — mọi trình duyệt tuân theo đặc tả giờ chỉ trả về một tập mục cố định giống nhau, hoặc không trả về gì cả. Nghe có vẻ như đó là dấu chấm hết cho một bề mặt lấy dấu vân tay từng phổ biến. Nhưng không hẳn vậy: một giá trị lẽ ra phải cố định lại trở nên có thông tin đúng vào lúc nó không cố định, hoặc khi nó mâu thuẫn với một API liên quan mô tả cùng một khả năng.
Tóm tắt nhanh
- Danh sách plugin không còn là dữ liệu thật. Các phiên bản đặc tả gần đây cố định cứng
navigator.plugins: nếu trình duyệt hỗ trợ xem PDF nhúng, nó liệt kê đúng năm mục cố định; nếu không, nó trả về mộtPluginArrayrỗng. navigator.pdfViewerEnabledlà cách được khuyến nghị chính thức để kiểm tra — MDN nói rõ không nên suy ra điều này từnavigator.plugins.- Danh sách vẫn mang một tín hiệu phát hiện, chỉ là không còn mang tính định danh. Một trình duyệt tự nhận là Chrome trên desktop nhưng trả về mảng rỗng, xuất hiện các mục thừa bất thường, hoặc
navigator.pluginsmâu thuẫn vớinavigator.pdfViewerEnabled— tất cả đều là lỗi nhất quán nội bộ, không phải sự biến thiên bình thường giữa các trình duyệt. - Tự thân nó,
navigator.pluginsgiờ mang entropy gần như bằng không — hầu như mọi trình duyệt thật đều rơi vào một trong hai trạng thái cố định, nên nó không còn phân biệt được các khách truy cập khác nhau như dấu vân tay canvas hay phông chữ vẫn làm được. Giá trị còn lại của nó là một phép kiểm tra tính nhất quán chồng lên các tín hiệu khác, chứ không phải một định danh độc lập. - Đây là một bề mặt hoàn toàn khác so với tiện ích mở rộng trình duyệt. Tiện ích mở rộng là phần bổ sung do người dùng tự cài, được phát hiện bằng phương pháp hoàn toàn khác;
navigator.pluginstừ trước đến nay chỉ mô tả lớp plugin/xử lý PDF tích hợp sẵn của chính trình duyệt.
navigator.plugins giờ thực sự trả về gì
Gọi navigator.plugins vẫn trả về một PluginArray — không phải mảng JavaScript thật, mà là một đối tượng giống mảng có length, item(index), và namedItem(name). Nhưng nội dung bên trong không còn được xác định từ hệ điều hành nữa. Theo đặc tả hiện tại, nội dung chỉ có thể là một trong đúng hai kết quả cố định:
- Nếu trình duyệt hỗ trợ xem PDF nhúng, mảng chứa năm mục cụ thể:
"PDF Viewer","Chrome PDF Viewer","Chromium PDF Viewer","Microsoft Edge PDF Viewer", và"WebKit built-in PDF". - Nếu không hỗ trợ, mảng rỗng.
if ("PDF Viewer" in navigator.plugins) {
// Trình duyệt hỗ trợ xem PDF nhúng.
}
Chỉ có vậy thôi. Không có trạng thái thứ ba, không có danh sách một phần, và một trình duyệt thật tuân thủ đặc tả không thể nào báo cáo ba plugin hay một plugin mang tên khác. MDN đánh dấu PluginArray là lỗi thời — một ứng viên sẽ bị loại bỏ trong tương lai — và các thuộc tính của chính nó không còn liệt kê được (enumerable) trong các phiên bản trình duyệt hiện tại, điều này chặn đứng thủ thuật cũ dùng vòng lặp for...in để duyệt qua mảng.
navigator.mimeTypes đã trải qua thay đổi giống hệt. Nó trả về một MimeTypeArray, theo đặc tả chứa các mục application/pdf và text/pdf khi hỗ trợ xem PDF nhúng, và danh sách rỗng nếu không — cố định theo cùng cách, gắn với đúng một bit khả năng nền tảng như nhau.
navigator.pdfViewerEnabled mới là bản thay thế — không phải navigator.plugins
Chính vì danh sách plugin đã thu gọn thành một tín hiệu có/không duy nhất về khả năng hỗ trợ PDF, nền tảng đã bổ sung một thuộc tính nói thẳng điều đó: navigator.pdfViewerEnabled, một giá trị boolean đơn giản. MDN nói rõ về hướng chuyển đổi này trên cả hai trang plugins và mimeTypes: hãy dùng navigator.pdfViewerEnabled để xác định trình duyệt có hỗ trợ xem PDF nhúng hay không, và đừng suy luận điều đó từ hai thuộc tính cũ này.
Chính hướng dẫn đó là lý do navigator.plugins vẫn đáng để bàn tới. Đoạn mã hợp lệ muốn biết "trình duyệt này có hiển thị PDF nhúng được không" giờ đã có câu trả lời trực tiếp, được chính thức công nhận. Còn đoạn mã vẫn rẽ nhánh dựa trên navigator.plugins.length hoặc tìm "PDF Viewer" theo tên, thì hoặc là mã cũ, hoặc đang làm một việc khác chẳng liên quan gì đến hỗ trợ PDF — và đó chính xác là kiểu mã mà một công cụ phát hiện muốn nhận diện.
Vì sao một danh sách cố định vẫn là tín hiệu phát hiện
Một giá trị chỉ có hai trạng thái hợp lệ tự nó không thể định danh khách truy cập — nhưng nó có thể bắt được một môi trường trình duyệt không hành xử đúng như những gì nó tự nhận. Đó là toàn bộ giá trị còn lại, và nó nằm ở tính nhất quán nội bộ chứ không phải tính duy nhất:
Mảng rỗng ở nơi lẽ ra phải đầy đủ. Một chuỗi User-Agent tự nhận là Chrome desktop hiện đại, theo đặc tả lẽ ra phải trả về đúng danh sách năm mục trình xem PDF đó — vì các bản Chrome gần đây mặc định bật xem PDF nhúng. navigator.plugins rỗng trên một cấu hình tự nhận như vậy là một điểm lệch đáng chú ý, và đây chính là loại khoảng trống mà môi trường trình duyệt headless và tự động hóa từ trước đến nay hay để lộ, đôi khi vì bộ công cụ tự động hóa vô hiệu hóa hoàn toàn thành phần trình xem PDF.
Các mục không khớp với tập cố định. Vì đặc tả cố định cứng đúng năm tên plugin, bất kỳ mục plugin nào nằm ngoài tập đó — một cái tên lạ, một số lượng khác, một mục hiển thị [object Object] thay vì chuỗi văn bản — đều cho thấy thuộc tính này đã bị một script chỉnh sửa, chứ không phải do trình duyệt tự tạo ra. Trớ trêu thay, chính các công cụ tự động hóa ẩn mình (stealth) cố dựng một danh sách plugin "trông thật" lại là thứ dễ tạo ra một danh sách lệch khỏi những gì trình duyệt thật, đời mới thực sự trả về nhất. Bản vá đó thường để lại thêm một dấu vết thứ hai: thay thuộc tính này bằng một object thường hay một mảng JavaScript sẽ trượt những phép kiểm tra mà một navigator.plugins nguyên bản luôn vượt qua — prototype của nó vẫn là PluginArray, String(navigator.plugins) vẫn cho ra "[object PluginArray]", và các phương thức của nó khi chuyển thành chuỗi vẫn là mã native.
navigator.plugins và navigator.pdfViewerEnabled mâu thuẫn nhau. Hai thuộc tính này mô tả cùng một khả năng nền tảng, chỉ khác là đến từ hai giai đoạn khác nhau của đặc tả. Trên một trình duyệt thật, chưa bị chỉnh sửa, chúng luôn thống nhất: danh sách plugin không rỗng đồng nghĩa pdfViewerEnabled === true, và ngược lại. Một trang truy vấn cả hai và phát hiện chúng mâu thuẫn nhau — pdfViewerEnabled là true trong khi navigator.plugins rỗng, hoặc ngược lại — đã bắt được một đoạn script chỉ chỉnh sửa thuộc tính mà nó biết đến: mã giả mạo thường chỉ vá thuộc tính cũ quen thuộc và quên mất rằng còn một thuộc tính mới hơn.
Không phép kiểm tra nào trong số này nói lên khách truy cập là ai. Chúng chỉ nói rằng môi trường đang thiếu nhất quán nội bộ — và đó chính là dấu vết mà các hồ sơ trình duyệt tự động hóa và giả mạo để lại thường xuyên hơn nhiều so với trình duyệt thật.
Không phải cùng bề mặt với tiện ích mở rộng trình duyệt
Rất dễ nhầm lẫn giữa "plugin" và "tiện ích mở rộng" vì cả hai đều là phần bổ sung cho trình duyệt về mặt lịch sử, nhưng cách phát hiện và ý nghĩa của chúng hoàn toàn khác nhau. navigator.plugins mô tả kiến trúc plugin và xử lý PDF tích hợp sẵn của chính trình duyệt, giờ đã thu gọn thành đúng một tín hiệu PDF cố định đó. Tiện ích mở rộng trình duyệt (uBlock Origin, trình quản lý mật khẩu, trình chặn quảng cáo) là phần mềm do người dùng tự cài, và một trang hoàn toàn không thể liệt kê chúng qua API này — phát hiện tiện ích mở rộng đã cài đặt dựa vào các kỹ thuật riêng, chẳng hạn dò xem tài nguyên có thể truy cập công khai (web-accessible) của chính tiện ích đó có phản hồi hay không. Nếu bạn quan tâm đến việc một trang có thể biết gì về các tiện ích mở rộng người dùng đã cài, thay vì cờ plugin tích hợp sẵn này của trình duyệt, hãy xem bài viết của chúng tôi về rủi ro quyền riêng tư của tiện ích mở rộng trình duyệt.
Kiểm tra thực tế về entropy
Cần nói thẳng rằng navigator.plugins tự thân đóng góp rất ít ngày nay. Với chỉ hai trạng thái hợp lệ trên mọi trình duyệt tuân thủ đặc tả, nó gần như không thêm thông tin phân biệt nào — không thể so sánh với mức đóng góp của kết xuất canvas, danh sách phông chữ đã cài, hay các tham số WebGL. Một số bài viết cũ về lấy dấu vân tay trình duyệt vẫn mô tả navigator.plugins như một tín hiệu phong phú theo từng người dùng — điều đó đúng trước khi có thay đổi cố định hóa; xem nó theo cách đó ngày nay là đánh giá quá cao vai trò của nó. Công việc hữu ích của nó bây giờ hẹp hơn và cũng khác về bản chất: không phải "đây là ai", mà là "các tín hiệu về hỗ trợ PDF của môi trường này có khớp với nhau, và khớp với danh tính mà nó tự nhận, hay không". Điều này đặt nó vào cùng nhóm với lấy dấu vân tay trạng thái Permissions API — một phép đọc khác không cần cửa sổ hỏi, không cần cú nhấp chuột, hữu ích hơn khi dùng làm phép kiểm tra nhất quán thay vì nguồn entropy thô. Nó còn kém xa các tín hiệu vẫn thực sự phân biệt được thiết bị thật, như danh sách camera và micro mà enumerateDevices() để lộ. Để có bức tranh đầy đủ về những tín hiệu nào vẫn mang giá trị phân biệt thực sự, hãy xem hướng dẫn đầy đủ về lấy dấu vân tay trình duyệt của chúng tôi.
Kiểm tra trình duyệt của chính bạn
Với công cụ kiểm tra plugin của BrowserInsight, bạn có thể thấy chính xác trình duyệt của mình báo cáo gì về thuộc tính này: từng mục cụ thể, số lượng, và trình xem PDF có đang bật hay không. Công cụ này cũng chạy luôn phần kiểm tra tính nhất quán — danh sách plugin có khớp với navigator.mimeTypes không, và đối tượng PluginArray trông còn nguyên bản hay đã bị chỉnh sửa — cùng với các phép kiểm tra tiện ích mở rộng tiếp nối ngay sau navigator.plugins. Để đặt thuộc tính này trong bức tranh đầy đủ cùng canvas, WebGL, phông chữ và mọi tín hiệu khác mà một trang có thể đọc, hãy dùng kiểm tra dấu vân tay.
Câu hỏi thường gặp
navigator.plugins rỗng trên trình duyệt hiện đại có bình thường không?
Có. Mảng rỗng chỉ đơn giản nghĩa là trình duyệt báo không hỗ trợ xem PDF nhúng trong cấu hình mặc định — đó là một trạng thái hợp lệ, tuân theo đặc tả, tự nó không phải dấu hiệu bị chỉnh sửa. Nó chỉ đáng chú ý khi đặt cạnh các tín hiệu khác, chẳng hạn khi một User-Agent tự nhận là phiên bản trình duyệt lẽ ra phải hỗ trợ PDF nhúng.
Tôi vẫn có thể dùng navigator.plugins để kiểm tra hỗ trợ PDF không?
Về mặt kỹ thuật thì được, nhưng không nên — MDN khuyến nghị rõ ràng dùng navigator.pdfViewerEnabled cho việc kiểm tra này thay thế. Cả navigator.plugins và navigator.mimeTypes đều đang là ứng viên cho việc loại bỏ trong tương lai.
Vì sao danh sách navigator.plugins của một bot lại trông sai?
Vì danh sách thật, tuân theo đặc tả chỉ có đúng hai hình dạng khả dĩ, nên bất kỳ script nào cố gắng chèn một danh sách plugin tự soạn "trông có vẻ thật" để giả làm người dùng thật đều đang đối đầu với một mục tiêu đã bị cố định: bên phát hiện vốn đã biết danh sách thật trông ra sao, nên bất cứ thứ gì lệch khỏi nó đều lộ ra ngay. Một danh sách plugin ghép thủ công nhiều khả năng để lộ tự động hóa hơn là che giấu nó — nhất là khi nó không khớp với navigator.pdfViewerEnabled, hoặc khi đối tượng bị thay thế trông không còn giống một PluginArray native nữa.
navigator.plugins còn ý nghĩa gì cho việc lấy dấu vân tay không?
Rất ít, và không còn theo cách như trước nữa. Đóng góp entropy tự thân của nó gần như bằng không. Giá trị còn lại của nó là một phép kiểm tra nhất quán giữa navigator.pdfViewerEnabled và danh tính mà trình duyệt tự nhận, chứ không phải cách để phân biệt hai khách truy cập.


