Фингерпринтинг синтеза речи: отслеживание голосов
Как список голосов SpeechSynthesis API раскрывает вашу операционную систему и платформу, и методы контроля голосовых сигналов отпечатка.
Нужна поддерживаемая продуктовая документация?
У этой статьи есть соответствующая страница в центре документации. Используйте docs для каноничного сценария настройки, актуальных флагов и долгосрочной справки.
Введение
Интерфейс SpeechSynthesis Web Speech API был разработан для предоставления веб-приложениям возможностей преобразования текста в речь. Он позволяет разработчикам конвертировать текст в аудио, обеспечивая функции доступности, инструменты изучения языков и интерактивные голосовые интерфейсы. Метод speechSynthesis.getVoices() возвращает список доступных голосов, каждый со свойствами вроде имени, языка и информации о том, работает ли он локально или через удаленный сервис.
Хотя API служит четкой цели доступности, список голосов, который он раскрывает, значительно различается между операционными системами, версиями браузеров и установленными языковыми пакетами. Система Windows 11 может сообщить более 40 голосов, включая Microsoft David, Zira и различные голоса Cortana. Система macOS сообщает совершенно другие голоса вроде Alex, Samantha и ряд голосов на основе Siri. Системы Linux, использующие speech-dispatcher, сообщают ещё один набор. Эта платформенно-специфичная вариация делает список голосов надежным сигналом для идентификации базовой операционной системы и конфигурации.
Влияние на конфиденциальность
Список голосов SpeechSynthesis является особенно эффективным вектором снятия отпечатков, потому что сочетает высокую энтропию с низкой осведомленностью. Большинство пользователей не знают, что веб-сайты могут перечислить их установленные голоса преобразования текста в речь, и нет запроса разрешения или уведомления при этом.
Проблема конфиденциальности выходит за рамки простой идентификации ОС. Списки голосов различаются не только по операционной системе, но и по:
- Версии ОС: Windows 10 и Windows 11 поставляются с разными наборами голосов по умолчанию. macOS Ventura и macOS Sonoma включают разные голоса Siri.
- Языковым пакетам: пользователи, устанавливающие дополнительные языковые пакеты, получают новые голоса, создавая более отличительный отпечаток.
- Стороннему ПО TTS: приложения вроде Balabolka, NaturalReader или экранных читалок NVDA могут добавлять голоса в систему, ещё больше различая устройство.
- Версии браузера: Chrome, Firefox и Edge каждый раскрывают разные подмножества доступных системных голосов.
Исследование 2021 года от учёных Университета Айовы показало, что списки голосов синтеза речи в сочетании с другими сигналами браузера могут увеличить уникальность отпечатков на 12-18% по сравнению со снятием отпечатков без данных голосов. Список голосов особенно ценен, потому что раскрывает информацию об операционной системе, которую иначе трудно получить после усилий по сокращению User-Agent.
Событие onvoiceschanged добавляет ещё одно измерение: наблюдая за тем, когда и как загружается список голосов, трекеры могут вывести информацию о последовательности внутренней инициализации браузера, которая различается между платформами.
Техническая основа
Как формируются списки голосов
Когда браузер запускается, он запрашивает подсистему преобразования текста в речь операционной системы для получения доступных голосов. На Windows это означает Speech API (SAPI) и более современную речевую платформу OneCore. На macOS браузер запрашивает фреймворк NSSpeechSynthesizer. На Linux он обычно использует speech-dispatcher или напрямую запрашивает установленные движки вроде eSpeak, Festival или Piper.
Каждый объект голоса, возвращаемый speechSynthesis.getVoices(), имеет несколько свойств:
name: отображаемое имя голоса (например, "Microsoft David - English (United States)")lang: языковой тег BCP 47 (например, "en-US")localService: работает ли голос локально (true) или требует сетевого подключения (false)voiceURI: URI, идентифицирующий голосdefault: является ли это голосом по умолчанию для его языка
Платформенно-специфичные сигнатуры голосов
Список голосов действует как сигнатура платформы. Стандартная установка Windows 11 сообщает голоса с именами, начинающимися с "Microsoft", и включает платформенно-специфичные варианты. macOS сообщает голоса с Apple-специфичными именами и включает голоса Siri на последних версиях. Chrome на Android сообщает совершенно другой набор, часто включая голоса бренда Google.
Это создает матрицу идентификаторов: количество голосов, их точные имена, покрытие языков и разделение на локальные/удалённые - всё вносит вклад в платформенный отпечаток. Даже порядок, в котором голоса появляются в массиве, может различаться между платформами.
Асинхронное поведение загрузки
Загрузка голосов асинхронна в большинстве браузеров. Первый вызов getVoices() может вернуть пустой массив, а полный список становится доступен после срабатывания события voiceschanged. Время этого события и то, возвращает ли getVoices() пустой список изначально, различается между браузерами и платформами. Само это поведение загрузки является сигналом снятия отпечатков.
Сетевые голоса
Некоторые браузеры включают голоса на основе сети, требующие подключения к интернету. Доступность этих голосов зависит от браузера, статуса аккаунта Google пользователя (для Chrome) и сетевого подключения. Наличие или отсутствие сетевых голосов добавляет ещё один слой к отпечатку.
Распространенные подходы к защите и их ограничения
VPN и прокси-серверы
VPN меняют IP-адрес, но не влияют на список голосов синтеза речи. Данные голосов берутся из локальной операционной системы, а не из сети. Два устройства за одним VPN сообщают совершенно разные списки голосов на основе своих конфигураций ОС и языков.
Инкогнито и приватный просмотр
Режимы приватного просмотра не изменяют список голосов. Те же голоса доступны в инкогнито, как и в обычном окне, потому что список голосов читается из операционной системы, а не из хранилища браузера.
Расширения браузера
Расширения, модифицирующие speechSynthesis.getVoices(), сталкиваются с несколькими проблемами:
- Подмена возвращаемого значения: расширение может переопределить
getVoices()для возврата пользовательского списка голосов, но сообщаемые голоса должны быть используемыми. Если веб-сайт попытается использовать сообщённый голос, а он не работает, несоответствие очевидно. - Тайминг событий: поведение события
voiceschangedтрудно контролировать из расширения. Тайминг события, сколько раз оно срабатывает и начальное поведение с пустым массивом - всё это платформенно-специфичные сигналы, которые расширения с трудом воспроизводят точно. - Дескрипторы свойств: переопределение
getVoices()через JavaScript, инжектированный расширением, изменяет дескрипторы свойств и цепочку прототипов функции, что может быть обнаружено.
Блокировка API
Полное отключение speechSynthesis обнаруживаемо: веб-сайт может проверить, существует ли API и возвращает ли он результаты. Браузер, который сообщает speechSynthesis как доступный, но не возвращает голосов, сам по себе является отличительным сигналом.
Подход BotBrowser на уровне движка
BotBrowser контролирует списки голосов синтеза речи на уровне движка браузера. При загрузке профиля отпечатков список голосов настраивается для соответствия целевой платформе профиля до выполнения любого кода страницы.
Списки голосов, контролируемые профилем
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Когда загружен профиль, представляющий систему Windows 11, speechSynthesis.getVoices() возвращает точный список голосов, ожидаемый на этой платформе, включая корректные имена, языки, флаги localService и порядок. Это верно независимо от фактической операционной системы хоста.
Кроссплатформенная согласованность
Именно здесь подход BotBrowser на уровне движка представляет наибольшую ценность. Запуск профиля Windows на Linux-сервере обычно раскрывает нативные голоса Linux (eSpeak, Festival), немедленно показывая, что браузер работает не на заявленной платформе. BotBrowser заменяет список голосов на ожидаемые голоса профиля, поддерживая согласованность платформы по всем поверхностям отпечатков.
Список голосов согласуется с другими платформенными сигналами:
navigator.platformсовпадает с ОС профиля- Строка User-Agent сообщает корректную платформу
- Списки шрифтов соответствуют целевой ОС
- Другие ОС-зависимые API сообщают согласованные значения
- Голоса синтеза речи соответствуют всему вышеперечисленному
Реалистичное поведение голосов
BotBrowser не просто возвращает статический список. Поведение загрузки голосов, включая тайминг асинхронного события voiceschanged и начальный паттерн возврата getVoices(), соответствует ожидаемому поведению для целевого браузера и платформы профиля. Это обеспечивает согласованность как данных, так и поведения загрузки.
Точность объектов голосов
Каждый объект голоса в возвращаемом списке имеет точные свойства: корректный формат name, подходящие теги lang, правильные значения localService и реалистичные строки voiceURI. Данные профиля снимаются с реальных устройств, обеспечивая соответствие каждого свойства тому, что сообщила бы настоящая установка.
Настройка и использование
Базовое использование CLI
Защита списка голосов автоматическая при загрузке профиля:
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Никакие дополнительные флаги не нужны. Профиль содержит полный список голосов для целевой платформы.
Интеграция с Playwright
const { chromium } = require('playwright-core');
(async () => {
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
],
headless: true,
});
const context = await browser.newContext({ viewport: null });
const page = await context.newPage();
const voices = await page.evaluate(() => {
return new Promise(resolve => {
const v = speechSynthesis.getVoices();
if (v.length > 0) return resolve(v.map(voice => ({
name: voice.name, lang: voice.lang, local: voice.localService,
})));
speechSynthesis.onvoiceschanged = () => {
resolve(speechSynthesis.getVoices().map(voice => ({
name: voice.name, lang: voice.lang, local: voice.localService,
})));
};
});
});
console.log(`Voice count: ${voices.length}`);
console.log('Voices:', JSON.stringify(voices, null, 2));
await browser.close();
})();
Интеграция с Puppeteer
const puppeteer = require('puppeteer-core');
(async () => {
const browser = await puppeteer.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
],
headless: true,
defaultViewport: null,
});
const page = await browser.newPage();
await page.goto('about:blank');
const voiceCount = await page.evaluate(() => {
return new Promise(resolve => {
const check = () => {
const voices = speechSynthesis.getVoices();
if (voices.length > 0) resolve(voices.length);
else speechSynthesis.onvoiceschanged = () =>
resolve(speechSynthesis.getVoices().length);
};
check();
});
});
console.log('Voices available:', voiceCount);
await browser.close();
})();
Верификация
После запуска BotBrowser с профилем проверьте список голосов:
function getVoices() {
return new Promise((resolve) => {
const voices = speechSynthesis.getVoices();
if (voices.length > 0) return resolve(voices);
speechSynthesis.onvoiceschanged = () =>
resolve(speechSynthesis.getVoices());
});
}
const voices = await getVoices();
console.log(`Voice count: ${voices.length}`);
voices.forEach(v =>
console.log(`${v.name} (${v.lang}) local: ${v.localService}`)
);
Что проверять:
- Количество голосов соответствует ожидаемому для целевой платформы профиля
- Имена голосов используют корректное соглашение об именовании платформы (например, префикс "Microsoft" для Windows)
- Языковые теги подходят для целевой конфигурации локали
- Свойство
localServiceсогласовано с ожидаемыми типами голосов платформы - Список голосов не содержит голосов из операционной системы хоста
- Инструменты тестирования отпечатков не показывают кросс-сигнальных несоответствий между данными голосов и другими индикаторами платформы
Лучшие практики
-
Всегда используйте полный профиль. Защита списка голосов зависит от предоставления профилем точных данных о голосах для целевой платформы. Частичные или пользовательские конфигурации могут производить неполные списки голосов.
-
Проверяйте кроссплатформенную согласованность. При запуске профилей на ОС, отличной от целевой, убедитесь, что список голосов соответствует целевой платформе, а не хосту. Это наиболее частый источник утечек голосовых отпечатков.
-
Учитывайте выравнивание по локали. Профиль, настроенный для японской локали, должен включать японские голоса. Профили BotBrowser, снятые с реальных устройств, включают подходящие локально-специфичные голоса.
-
Не устанавливайте расширения TTS наряду с BotBrowser. Сторонние расширения TTS для браузера могут регистрировать дополнительные голоса, конфликтующие с контролируемым списком голосов профиля.
Часто задаваемые вопросы
Все ли браузеры раскрывают один и тот же список голосов?
Нет. Chrome, Firefox, Edge и Safari каждый раскрывают разные подмножества доступных системных голосов. Профили BotBrowser специфичны для браузера, поэтому профиль Chrome возвращает голоса, подходящие для Chrome, а профиль Edge возвращает голоса, подходящие для Edge.
Могут ли веб-сайты реально использовать голоса для синтеза?
Защита списка голосов BotBrowser предназначена для согласованности отпечатков. Фактическая функциональность преобразования текста в речь зависит от возможностей системы хоста. В большинстве автоматизированных рабочих процессов воспроизведение TTS не нужно, но список голосов должен присутствовать и быть точным для согласованности отпечатков.
Меняется ли список голосов между версиями браузера?
Да. Обновления браузера иногда добавляют или удаляют поддержку голосов. Профили BotBrowser версионированы и включают список голосов, ожидаемый для конкретной версии браузера, которую представляет профиль.
Сколько голосов обычно сообщает типичная платформа?
Windows 11 обычно сообщает 30-50 голосов в зависимости от установленных языковых пакетов. macOS сообщает 60-80 голосов, включая варианты Siri. Chrome на Android сообщает 5-15 голосов. Точное количество является одним из сигналов снятия отпечатков, которые контролирует BotBrowser.
Работает ли защита списка голосов в безголовом режиме?
Да. BotBrowser применяет список голосов профиля независимо от того, работает ли браузер в обычном или безголовом режиме. Это важно, потому что безголовые среды обычно не имеют подсистемы TTS, и пустой список голосов в безголовом режиме является сильным сигналом обнаружения.
Как насчет таймингов события voiceschanged?
BotBrowser контролирует тайминг и поведение события voiceschanged для соответствия ожидаемому паттерну целевой платформы профиля. Это включает то, возвращает ли getVoices() изначально пустой массив и как быстро срабатывает событие после загрузки страницы.
Итоги
Список голосов SpeechSynthesis API является высокоэнтропийным сигналом снятия отпечатков, раскрывающим операционную систему, версию браузера и конфигурацию языков. Стандартные инструменты конфиденциальности не могут его решить, потому что данные о голосах берутся из ОС, а не из сети или хранилища браузера. BotBrowser контролирует списки голосов на уровне движка через систему профилей, обеспечивая кроссплатформенную согласованность и выравнивание со всеми другими сигналами отпечатков. Смежные темы: navigator properties protection, font fingerprint control и timezone and locale configuration.
Похожие статьи
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.