speechSynthesis.getVoices() tiết lộ danh sách giọng tổng hợp đã cài đặt mà không cần lời nhắc quyền — một tín hiệu ổn định, hiếm khi bị chặn.
Mọi hệ điều hành đều đi kèm một bộ giọng chuyển văn bản thành giọng nói (text-to-speech) tích hợp sẵn, và mọi trình duyệt đều tiết lộ toàn bộ danh sách đó cho bất kỳ trang nào yêu cầu — không cần nhấp chuột, không cần hộp thoại xin quyền, không có lời nhắc kiểu camera. window.speechSynthesis.getVoices() được tạo ra để trình đọc màn hình và các tính năng đọc to có thể chọn một giọng, nhưng danh sách nó trả về cũng đồng thời là một tín hiệu vân tay âm thầm mà khá hiệu quả: nó phản ánh đồng thời hệ điều hành, gói ngôn ngữ và nhà cung cấp trình duyệt của bạn — và không hề thay đổi khi xóa cookie.
Điểm chính
speechSynthesis.getVoices()không cần bất kỳ quyền nào và trả về toàn bộ danh sách giọng tổng hợp đã cài đặt cho bất kỳ script nào gọi nó.- Mỗi giọng tiết lộ các trường
name,lang,localServicevàdefault— và tập hợp, thứ tự và số lượng giọng thay đổi tùy theo hệ điều hành, gói ngôn ngữ đã cài đặt và nhà cung cấp trình duyệt. - Danh sách này thường được tải bất đồng bộ: lần gọi đầu tiên có thể trả về mảng rỗng, và script phải chờ sự kiện
voiceschangedmới thấy được danh sách thực — và bản thân hành vi này cũng khác nhau giữa các trình duyệt. - Danh sách giọng có thể được đối chiếu chéo với hệ điều hành và trình duyệt bạn khai báo, giống như chuỗi GPU — một User-Agent "macOS Safari" nhưng lại có danh sách giọng chỉ dành cho Windows là một tín hiệu không khớp đáng chú ý.
- Tín hiệu này ổn định qua nhiều phiên, không bị ảnh hưởng bởi việc xóa cookie hay chế độ duyệt web riêng tư, vì nó đến từ phần mềm đã cài đặt chứ không phải dữ liệu lưu trữ.
Vân tay tổng hợp giọng nói là gì?
Vân tay tổng hợp giọng nói đọc danh sách giọng chuyển văn bản thành giọng nói mà trình duyệt của bạn có thể thấy thông qua giao diện tổng hợp của Web Speech API, cùng họ API vốn cũng là nền tảng cho trình đọc màn hình và các tiện ích mở rộng đọc to trang web. Bản thân lệnh gọi, SpeechSynthesis.getVoices(), là đồng bộ, không cần quyền, và trả về một mảng đối tượng SpeechSynthesisVoice mô tả từng giọng mà trình duyệt có thể chuyển cho speak().
Không có gì được phát ra và không có âm thanh nào được tạo ra trong quá trình thu thập — đây là một lần đọc kho hàng thuần túy, về bản chất gần với liệt kê phông chữ hoặc liệt kê thiết bị đa phương tiện hơn là vân tay âm thanh hay Canvas, vốn đo lường cách một thứ gì đó được kết xuất. Ở đây, điều quan trọng chỉ đơn giản là những tài nguyên tùy chọn có tên nào đã được cài đặt — và danh sách đó khác nhau đủ nhiều giữa các máy để hữu ích ngay cả khi đứng một mình, và càng hữu ích hơn khi kết hợp với các tín hiệu khác.
Mỗi giọng tiết lộ điều gì
Mỗi phần tử trong mảng là một SpeechSynthesisVoice với bốn trường có thể đọc được:
name— nhãn dễ đọc, chẳng hạn "Microsoft David - English (United States)" hoặc "Samantha"lang— thẻ ngôn ngữ BCP 47, chẳng hạnen-UShoặcvi-VNlocalService—truenếu giọng được xử lý ngay trên thiết bị,falsenếu phụ thuộc vào một dịch vụ mạng từ xa (phổ biến ở một số giọng Google đi kèm Chrome)default—truecho giọng mà trình duyệt sẽ chọn nếu không chỉ định giọng nào
function getVoiceFingerprint() {
const voices = speechSynthesis.getVoices();
return voices
.map(v => `${v.name}|${v.lang}|${v.localService}`)
.sort()
.join(';');
}
Script hoàn toàn không cần gọi speak() — chỉ cần đọc mảng và băm các bộ ba name/lang/localService đã sắp xếp là đủ để tạo ra một định danh ổn định cho kho giọng của máy đó.
Cạm bẫy tải bất đồng bộ
Trở ngại duy nhất mà kẻ theo dõi (và cả lập trình viên) phải giải quyết là thời điểm. Trên một số trình duyệt, gọi getVoices() ngay sau khi trang tải xong sẽ trả về mảng rỗng, vì trình duyệt chưa kịp hỏi hệ điều hành về các giọng đã cài đặt. Cách khắc phục được ghi trong tài liệu MDN là lắng nghe sự kiện voiceschanged và đọc lại danh sách khi nó được kích hoạt:
function collectVoicesReliably() {
return new Promise((resolve) => {
let voices = speechSynthesis.getVoices();
if (voices.length) return resolve(voices);
speechSynthesis.onvoiceschanged = () => {
resolve(speechSynthesis.getVoices());
};
});
}
Cạm bẫy này không chỉ là một điều phiền toái với lập trình viên — bản thân nó cũng là một tín hiệu vân tay. Việc một trình duyệt có cần giải pháp voiceschanged hay không, và danh sách mất bao lâu để được điền đầy, khác nhau tùy theo engine trình duyệt và nền tảng, thêm một chiều nhỏ nữa ngoài chính danh sách giọng.
Mức độ đặc trưng và ổn định ra sao?
Kho giọng thay đổi theo ba trục độc lập với nhau, mỗi trục đều tạo thêm sự phân tách giữa các hồ sơ:
| Trục | Vì sao thay đổi |
|---|---|
| Hệ điều hành | Windows, macOS và Linux mỗi hệ đi kèm một bộ giọng mặc định khác nhau với tên gọi khác nhau |
| Gói ngôn ngữ đã cài đặt | Một máy được thiết lập cho nhiều ngôn ngữ tiết lộ nhiều giọng hơn một bản cài đặt mặc định một ngôn ngữ |
| Nhà cung cấp trình duyệt | Một số trình duyệt bổ sung giọng riêng đi kèm hoặc phụ thuộc mạng (localService: false) bên trên danh sách của hệ điều hành; số khác chỉ tiết lộ những gì hệ điều hành cung cấp |
Vì danh sách này phản ánh phần mềm thực sự đã cài đặt chứ không phải một đặc điểm kỳ lạ trong kết xuất, nó hoạt động ít giống một nguồn nhiễu ngẫu nhiên theo từng thiết bị hơn, mà giống một kho hàng có cấu trúc hơn — gần với việc kiểm tra "phông chữ nào đã cài đặt" hơn là "GPU này làm tròn số thực dấu phẩy động ra sao". Một bản cài đặt mặc định một ngôn ngữ tạo ra một danh sách ngắn, phổ biến, được nhiều máy tương tự chia sẻ; trong khi một thiết lập người dùng thành thạo đa ngôn ngữ với nhiều gói giọng đã cài đặt lại nổi bật. Kết hợp với các tín hiệu như WebGL và phông chữ đã cài đặt, nó thêm một trục gần như độc lập nữa vào dấu vân tay tổng thể, theo cùng logic tổ hợp được nêu trong hướng dẫn về vân tay trình duyệt của chúng tôi: không tín hiệu đơn lẻ nào mang tính quyết định, nhưng các tín hiệu độc lập nhân lên với nhau.
Nó cũng là một kiểm tra tính nhất quán hữu ích. Một danh sách giọng hoàn toàn gồm các tên theo phong cách SAPI của Windows đi kèm một User-Agent khai báo macOS chính là kiểu mâu thuẫn đánh dấu một hồ sơ bị giả mạo hoặc cấu hình sai, cùng loại với các trường hợp không khớp GPU/hệ điều hành trong bài Không khớp phần cứng vân tay — danh sách giọng phải nhất quán với mọi thứ khác mà trình duyệt báo cáo về chính nó.
Về độ ổn định, danh sách giọng hiếm khi thay đổi đối với một máy cụ thể. Nó chỉ dịch chuyển khi hệ điều hành cập nhật các giọng đi kèm, người dùng cài đặt hoặc gỡ bỏ gói ngôn ngữ, hoặc một bản cập nhật trình duyệt lớn bổ sung giọng mới — ngoài ra, nó là một định danh bền vững qua nhiều phiên mà việc xóa cookie, mở cửa sổ riêng tư, hay xóa bộ nhớ đệm đều không thể đặt lại.
Biện pháp giảm thiểu
- Cấu hình trình duyệt hướng đến quyền riêng tư. Các trình duyệt và chế độ được xây dựng quanh nguyên lý đồng nhất — cài đặt chống vân tay của Firefox và Tor Browser — nhằm chuẩn hóa hoặc hạn chế các bề mặt API mang tính đặc trưng cao theo thiết bị như thế này, với cái giá là hoạt động khác thường trên các trang mong đợi danh sách giọng đầy đủ.
- Hiểu rõ giới hạn của chế độ duyệt web riêng tư. Giống như vân tay âm thanh và Canvas, chế độ ẩn danh hay riêng tư không thay đổi phần mềm đã cài đặt, nên cũng không thay đổi danh sách giọng của bạn.
- Các tiện ích mở rộng chặn hoặc giả mạo Web Speech API có thể làm phẳng tín hiệu này, nhưng cần kiểm tra rằng chúng không chỉ đơn giản trả về một mảng rỗng theo cách mà bản thân điều đó cũng bất thường và do đó có thể nhận diện được — nghịch lý chống vân tay được nêu trong hướng dẫn về vân tay trình duyệt của chúng tôi cũng áp dụng ở đây.
Không có thiết lập nào có thể thu nhỏ danh sách giọng đã cài đặt của bạn xuống mức "phổ biến" mà không loại bỏ các gói ngôn ngữ bạn thực sự dùng, hoặc không chuyển sang một chế độ trình duyệt được xây dựng quanh việc hòa vào một đám đông đồng nhất lớn.
Cách kiểm tra tín hiệu của chính bạn
Bạn có thể xem dấu vân tay giọng nói của mình mà không cần viết bất kỳ dòng code nào:
- Chạy một công cụ kiểm tra vân tay. Công cụ kiểm tra vân tay của BrowserInsight hiển thị các tín hiệu mà trình duyệt của bạn tiết lộ cùng với Canvas, WebGL và âm thanh, còn dự án Cover Your Tracks của EFF cho thấy cấu hình tổng thể của bạn hiếm đến mức nào trong số các khách truy cập gần đây.
- So sánh giữa các trình duyệt trên cùng một máy. Mở bản demo
getVoices()trên MDN trên hai trình duyệt khác nhau trên cùng một máy tính — dù các giọng ở cấp hệ điều hành phần lớn trùng nhau, số lượng giọng và sự hiện diện của các mục phụ thuộc mạng (localService: false) thường khác nhau. - Kiểm tra hỗ trợ trình duyệt trước khi phụ thuộc vào nó. Mức độ hỗ trợ phần tổng hợp giọng nói của Web Speech API khá rộng nhưng không phổ quát trên các phiên bản trình duyệt cũ hơn — xem caniuse để biết tình trạng hỗ trợ hiện tại.
Câu hỏi thường gặp
speechSynthesis.getVoices() có cần lời nhắc quyền không?
Không. Khác với việc truy cập camera hay micro, việc đọc danh sách giọng đã cài đặt không cần quyền người dùng nào và không kích hoạt bất kỳ hộp thoại nào. Bất kỳ script nào trên bất kỳ trang nào cũng có thể gọi nó và đọc kết quả ngay lập tức (tùy thuộc vào cạm bẫy tải bất đồng bộ đã mô tả ở trên).
Tại sao getVoices() đôi khi trả về mảng rỗng?
Một số trình duyệt lấy danh sách giọng từ hệ điều hành một cách bất đồng bộ sau khi trang tải xong, nên gọi quá sớm sẽ không trả về gì. Cách khắc phục tiêu chuẩn là lắng nghe sự kiện voiceschanged và đọc lại danh sách khi nó kích hoạt, như trong ví dụ code ở trên.
Vân tay tổng hợp giọng nói có thể tự mình nhận diện tôi không?
Hiếm khi tự nó làm được — một tổ hợp hệ điều hành/trình duyệt đơn ngôn ngữ phổ biến tạo ra một danh sách giọng mà nhiều người cùng có. Nó trở nên có ý nghĩa khi kết hợp với các tín hiệu khác như phông chữ, Canvas và WebGL, và như một phép kiểm tra tính nhất quán với hệ điều hành bạn khai báo.
Xóa cookie hoặc dùng chế độ riêng tư có đặt lại vân tay giọng nói của tôi không?
Không. Danh sách giọng phản ánh phần mềm đã cài đặt trên thiết bị, chứ không phải dữ liệu trình duyệt lưu trữ, nên xóa cookie, dùng cửa sổ riêng tư, hoặc chuyển hồ sơ đều không làm nó thay đổi.
Kết luận
Vân tay tổng hợp giọng nói biến một API trình đọc màn hình dành cho khả năng tiếp cận thành một lần đọc âm thầm, không cần quyền, về danh sách giọng đã cài đặt của hệ điều hành và trình duyệt. Tự nó, nó chỉ phân nhóm thô các trình duyệt theo nền tảng và thiết lập ngôn ngữ; kết hợp với phông chữ, Canvas và WebGL, nó thêm một trục độc lập nữa vào dấu vân tay tổng thể — và thêm một phép kiểm tra tính nhất quán nữa. Cũng như hầu hết các bề mặt vân tay khác, không có công tắc đơn lẻ nào xóa sạch nó, chỉ có các chế độ trình duyệt và tiện ích mở rộng làm giảm mức độ nổi bật của nó.
Đọc thêm:

