Фингерпринтинг тайминга: аппаратные сигналы
Как точность Performance.now(), аппаратный параллелизм и память устройства становятся сигналами отслеживания и как контролировать их на уровне движка.
Нужна поддерживаемая продуктовая документация?
У этой статьи есть соответствующая страница в центре документации. Используйте docs для каноничного сценария настройки, актуальных флагов и долгосрочной справки.
Введение
Performance API является одним из самых фундаментальных браузерных интерфейсов, изначально спроектированным для помощи разработчикам в измерении времени загрузки страниц, диагностике узких мест и оптимизации пользовательского опыта. Функции вроде performance.now(), performance.mark() и performance.measure() предоставляют разработчикам высокоточные временные метки для бенчмаркинга выполнения кода. Наряду с этими функциями таймингов, свойства вроде navigator.hardwareConcurrency и navigator.deviceMemory сообщают количество ядер CPU устройства и доступный объем RAM.
Хотя эти API служат легитимным целям, они также раскрывают аппаратные характеристики, которые различаются между устройствами. Ноутбук с 8 ядрами CPU и 16 ГБ RAM производит измеримо отличающиеся результаты таймингов и аппаратные отчеты по сравнению с десктопом с 16 ядрами и 32 ГБ. Эти различия остаются стабильными между сессиями браузера, переживают очистку cookie и сохраняются в режиме инкогнито, что делает их надежными сигналами для отслеживания отдельных устройств.
Влияние на конфиденциальность
Сигналы таймингов производительности представляют особенно коварную форму снятия отпечатков, потому что они глубоко привязаны к физическим аппаратным характеристикам, которые пользователи не могут легко изменить. В отличие от cookie или локального хранилища, которые пользователи могут очистить, сигналы таймингов возникают из фундаментальной скорости, с которой устройство выполняет JavaScript, рендерит графику и обрабатывает данные.
Исследования из учреждений, включая Принстон и KU Leuven, продемонстрировали, что снятие отпечатков на основе таймингов может различать устройства с высокой точностью. Исследование 2019 года показало, что комбинация измерений performance.now() с значениями аппаратного параллелизма могла корректно идентифицировать возвращающихся посетителей более чем в 80% случаев, даже когда другие идентификаторы были очищены.
Проблема выходит за рамки отдельных сигналов. Когда трекер собирает navigator.hardwareConcurrency (ядра CPU), navigator.deviceMemory (RAM) и время выполнения микробенчмарков вместе, комбинированный отпечаток становится весьма отличительным. Устройство с 6 ядрами, 8 ГБ памяти и специфическим профилем скорости выполнения JavaScript значительно сужает окно идентификации. Эти сигналы не требуют разрешений пользователя, не генерируют запросов и невидимы для отслеживаемого человека.
Техническая основа
Для понимания того, почему тайминг производительности различается между устройствами, полезно рассмотреть, что влияет на скорость выполнения JavaScript и API, раскрывающие аппаратную информацию.
Performance.now() и высокоточное время
performance.now() возвращает высокоточную временную метку, измеренную в миллисекундах с микросекундной точностью. Фактическое разрешение зависит от мер безопасности браузера (многие браузеры уменьшают точность для предотвращения атак класса Spectre), но даже уменьшенная точность раскрывает характеристики таймингов, привязанные к тактовой частоте CPU, иерархии кэша и конвейеру инструкций.
Когда веб-сайт запускает микробенчмарк, например итерацию цикла 100 000 раз или вычисление хэшей SHA-256, время выполнения напрямую зависит от аппаратного обеспечения устройства. Быстрый десктопный CPU выполняет ту же работу быстрее мобильного процессора, и эта разница измерима и повторяема.
Аппаратный параллелизм
navigator.hardwareConcurrency возвращает количество логических ядер процессора, доступных браузеру. Это значение отражает физическую конфигурацию CPU и не меняется между сессиями. Распространенные значения от 2 (бюджетные мобильные) до 32 и более (высокопроизводительные рабочие станции). Распределение неравномерно: определенные количества ядер (4, 8, 12, 16) гораздо более распространены, что означает, что необычные значения становятся сильными идентификаторами.
Память устройства
navigator.deviceMemory возвращает приблизительный объем RAM устройства в гигабайтах, округленный до ближайшей степени двойки (0,25, 0,5, 1, 2, 4, 8). Хотя округление уменьшает точность, это значение все равно вносит вклад в общий отпечаток. Устройство, сообщающее 8 ГБ памяти с 8 ядрами, - это другой отпечаток, чем устройство с 4 ГБ и 4 ядрами.
Почему эти значения важны вместе
По отдельности каждый сигнал имеет ограниченную энтропию. Но в совокупности они формируют аппаратный профиль: конкретная скорость выполнения, конкретное количество ядер и конкретный класс памяти. При наложении на другие сигналы отпечатков вроде Canvas, WebGL и шрифтов характеристики таймингов вносят существенный вклад в идентификацию устройства.
Распространенные подходы к защите и их ограничения
VPN и прокси-серверы
VPN меняют ваш IP-адрес, но имеют нулевое влияние на тайминг производительности. Все измерения таймингов и запросы аппаратных свойств происходят локально внутри браузера. Два устройства за одним VPN все равно сообщают совершенно разные аппаратные профили и скорости выполнения.
Инкогнито и приватный просмотр
Режимы приватного просмотра очищают cookie и историю, но не модифицируют navigator.hardwareConcurrency, navigator.deviceMemory или скорость выполнения базового оборудования. Ваш отпечаток производительности в инкогнито идентичен отпечатку в обычном окне.
Расширения браузера
Расширения, пытающиеся изменить аппаратные свойства, сталкиваются с фундаментальными ограничениями. Они могут переопределить значения свойств JavaScript, инжектируя скрипты, но это создает несоответствия, которые легко обнаружить:
- Если
navigator.hardwareConcurrencyсообщает 4 ядра, а микробенчмарк Web Worker показывает 8 параллельных потоков, значения конфликтуют. - Если
navigator.deviceMemoryсообщает 2 ГБ, а таймингperformance.now()для операций с интенсивным использованием памяти согласуется с 16 ГБ (нет пауз сборщика мусора), несоответствие очевидно. - Инжектированные расширениями переопределения обнаруживаются через проверку дескрипторов свойств, цепочек прототипов или запуск кода в свежем контексте до выполнения расширений.
Рандомизация
Некоторые инструменты конфиденциальности рандомизируют значения таймингов, добавляя шум к performance.now(). Хотя это предотвращает стабильную идентификацию, случайный сдвиг временных меток нарушает легитимный мониторинг производительности и создает собственный детектируемый паттерн. Последовательность временных меток с искусственным дрожанием выглядит иначе, чем естественная аппаратная вариация.
Подход BotBrowser на уровне движка
BotBrowser использует принципиально другой подход к защите таймингов производительности. Вместо перехвата вызовов API или добавления шума постфактум, BotBrowser контролирует сигналы таймингов на уровне движка браузера для получения внутренне согласованных результатов, соответствующих полному профилю устройства.
Аппаратная идентичность на основе профиля
При загрузке профиля отпечатков BotBrowser настраивает все аппаратные значения для соответствия целевому устройству профиля:
chrome --bot-profile="/path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Это устанавливает navigator.hardwareConcurrency и navigator.deviceMemory в настроенные значения профиля. Это не переопределения JavaScript; они применяются на уровне движка до выполнения любого кода страницы. Проверки дескрипторов свойств, проверка прототипов и выполнение в свежем контексте все возвращают одинаковые значения, потому что сам движок их сообщает.
Масштаб таймингов производительности
BotBrowser предоставляет флаг --bot-time-scale для контроля кажущейся скорости выполнения JavaScript-операций:
chrome --bot-profile="/path/to/profile.enc" \
--bot-time-scale=0.92
Флаг принимает значение с плавающей точкой ниже 1.0 (типичный диапазон: 0.80-0.99). Значение масштаба 0.92 сжимает интервалы performance.now() на 8%, уменьшая сигналы временного смещения, которые могут идентифицировать устройство. Масштабирование применяется равномерно ко всем источникам таймингов, поэтому микробенчмарки, performance.mark() и performance.measure() все производят внутренне согласованные результаты, соответствующие одному аппаратному классу.
Зерна таймингов производительности
Представленный в марте 2026 года, --bot-time-seed (ENT Tier2) обеспечивает более детальную защиту таймингов производительности. В то время как --bot-time-scale сжимает интервалы таймингов для уменьшения сигналов смещения, --bot-time-seed контролирует распределение таймингов по отдельным операциям браузера.
chrome --bot-profile="/path/to/profile.enc" \
--bot-time-scale=1.0 \
--bot-time-seed=12345
--bot-time-seed=<integer> принимает целочисленное зерно от 1 до UINT32_MAX (0 отключает функцию). Каждое зерно создает уникальный, стабильный профиль производительности, который диверсифицирует тайминги по множеству операций браузера, обеспечивая каждому экземпляру уникальную и согласованную сигнатуру таймингов.
Зерно также покрывает посессионное перераспределение значений performance.getEntries(), performance.getEntriesByType("navigation") и performance.timing, делая паттерны навигационных таймингов уникальными для каждого зерна.
Это полностью детерминировано: одно и то же зерно всегда производит один и тот же отпечаток таймингов. В сочетании с --bot-time-scale вы получаете как макроуровневый контроль скорости, так и микроуровневое разнообразие таймингов.
Пример Playwright:
const { chromium } = require('playwright-core');
(async () => {
const browser = await chromium.launch({
executablePath: '/path/to/botbrowser/chrome',
args: [
'--bot-profile=/path/to/profile.enc',
'--bot-time-scale=1.0',
'--bot-time-seed=12345',
],
headless: true,
});
const context = await browser.newContext({ viewport: null });
const page = await context.newPage();
await page.goto('https://example.com');
// Распределение таймингов уникально для зерна 12345
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',
'--bot-time-scale=1.0',
'--bot-time-seed=12345',
],
headless: true,
defaultViewport: null,
});
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close();
})();
Кросс-сигнальная согласованность
Ключевое преимущество контроля на уровне движка - согласованность. Когда BotBrowser сообщает 4 ядра CPU и 4 ГБ памяти через профиль, характеристики таймингов выполнения JavaScript тоже выровнены с этим аппаратным классом. Web Workers выполняются с параллелизмом, согласованным с заявленным количеством ядер. Паттерны выделения памяти соответствуют заявленному классу памяти. Нет противоречий между тем, что браузер сообщает, и тем, как он фактически работает.
Детерминированный режим
Для тестирования, исследований и CI/CD-конвейеров BotBrowser поддерживает полностью детерминированный тайминг через флаг шумового зерна:
chrome --bot-profile="/path/to/profile.enc" \
--bot-time-scale=1.0 \
--bot-noise-seed=42 \
--user-data-dir="$(mktemp -d)"
Один и тот же профиль, масштаб времени и шумовое зерно производят идентичные отпечатки таймингов между сессиями, хостовыми машинами и операционными системами.
Настройка и использование
Базовое использование CLI
chrome --bot-profile="/path/to/profile.enc" \
--bot-time-scale=1.0 \
--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',
'--bot-time-scale=1.0',
],
headless: true,
});
const context = await browser.newContext({ viewport: null });
const page = await context.newPage();
await page.goto('https://example.com');
// Аппаратные значения и сигналы таймингов соответствуют загруженному профилю
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',
'--bot-time-scale=0.92',
'--bot-noise-seed=42',
],
headless: true,
defaultViewport: null,
});
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.close();
})();
Комбинированная конфигурация
Для комплексной защиты объедините контроль таймингов с другими настройками профиля:
chrome --bot-profile="/path/to/profile.enc" \
--bot-time-scale=1.0 \
--bot-noise-seed=42 \
--proxy-server="socks5://user:pass@proxy:1080" \
--bot-config-timezone="America/New_York" \
--bot-config-locale="en-US"
Верификация
После запуска BotBrowser с профилем проверьте, что аппаратные значения и тайминги контролируются:
// Проверка аппаратных свойств
console.log('CPU Cores:', navigator.hardwareConcurrency);
console.log('Device Memory:', navigator.deviceMemory, 'GB');
// Измерение согласованности таймингов
async function measureTiming() {
const results = [];
for (let i = 0; i < 5; i++) {
const start = performance.now();
for (let j = 0; j < 100000; j++) Math.sqrt(j);
results.push(performance.now() - start);
}
return results;
}
const timings = await measureTiming();
console.log('Timing samples:', timings);
console.log('Variance:', Math.max(...timings) - Math.min(...timings));
Что проверять:
navigator.hardwareConcurrencyсоответствует настроенному количеству ядер профиляnavigator.deviceMemoryсоответствует настроенной памяти профиля- Образцы таймингов показывают согласованное поведение между запусками с тем же профилем и зерном
- Публичные инструменты тестирования отпечатков (CreepJS, BrowserLeaks) не показывают аномалий
Лучшие практики
-
Всегда используйте полный профиль. Аппаратные значения, тайминги и другие сигналы должны быть выровнены. Профиль обеспечивает согласованность по всем поверхностям отпечатков.
-
Используйте
--bot-time-scaleосознанно. Установите масштаб для уменьшения временного смещения целевого аппаратного класса профиля. Типичные значения от 0.80 до 0.99. Более низкие значения сжимают интервалы таймингов более агрессивно. -
Используйте детерминированный режим для CI/CD. Комбинируйте
--bot-noise-seedс--bot-time-scaleдля воспроизводимых результатов в автоматизированных конвейерах тестирования. -
Сопоставляйте географию прокси с идентичностью профиля. Профиль, настроенный для устройства в США, должен использовать прокси в США. Согласованность таймингов в сочетании с несоответствующей геолокацией ослабляет общую когерентность отпечатка.
-
Избегайте смешивания с расширениями, модифицирующими тайминги. BotBrowser обрабатывает всю защиту таймингов нативно на уровне движка. Сторонние расширения, модифицирующие
performance.now()или аппаратные свойства, будут конфликтовать.
Часто задаваемые вопросы
Отличается ли точность performance.now() между браузерами?
Да. Разные браузеры реализуют разные уровни точности временных меток, частично как защиту от атак сторонних каналов класса Spectre. Chrome, Firefox и Safari каждый уменьшают точность по-разному. Система профилей BotBrowser учитывает характеристики ожидаемой точности целевого браузера.
Могут ли веб-сайты определить, что значения таймингов контролируются?
Если контроль таймингов применяется несогласованно (например, модификация performance.now(), но не Date.now() или performance.mark()), веб-сайты могут обнаружить расхождение. BotBrowser применяет масштабирование таймингов равномерно ко всем источникам таймингов на уровне движка, предотвращая кросс-API несоответствия.
Влияет ли --bot-time-scale на фактическую производительность страницы?
Нет. Флаг контролирует, как значения таймингов сообщаются, а не как быстро JavaScript фактически выполняется. Страницы загружаются и работают на полной скорости; только измерения, сообщаемые JavaScript, отражают масштабированный тайминг.
Как аппаратный параллелизм взаимодействует с Web Workers?
BotBrowser обеспечивает согласованность заявленного значения navigator.hardwareConcurrency с количеством Web Workers, которые могут работать параллельно. Профиль управляет обоими значениями вместе.
Можно ли использовать разные масштабы времени для разных профилей?
Да. Каждый экземпляр браузера использует свое значение --bot-time-scale. Вы можете запускать несколько экземпляров одновременно с разными профилями и разными характеристиками таймингов.
Как насчет таймингов SharedArrayBuffer?
SharedArrayBuffer в сочетании с Atomics может использоваться как высокоточный таймер. Контроль таймингов BotBrowser на уровне движка применяется и к каналам таймингов разделяемой памяти, поддерживая согласованность по всем методам измерения таймингов.
Переживают ли отпечатки таймингов обновления браузера?
На незащищенных браузерах - да. Отпечаток таймингов привязан к аппаратному обеспечению, а не к версии браузера. Профили BotBrowser версионированы, поэтому вы можете поддерживать согласованные характеристики таймингов при обновлениях профилей.
В чем разница между --bot-time-seed и --bot-time-scale?
Они служат взаимодополняющим целям. --bot-time-scale сжимает интервалы performance.now() (принимает значение с плавающей точкой ниже 1.0, типичный диапазон 0.80-0.99) для уменьшения сигналов временного смещения. --bot-time-seed контролирует распределение таймингов по отдельным операциям браузера, создавая уникальный пооперационный профиль таймингов для каждого значения зерна. Вы можете использовать оба вместе: --bot-time-scale задает сжатие таймингов на макроуровне, а --bot-time-seed добавляет разнообразие таймингов на микроуровне в рамках этого профиля.
Итоги
API таймингов производительности раскрывают аппаратные характеристики, служащие стабильными сигналами отслеживания. performance.now(), navigator.hardwareConcurrency и navigator.deviceMemory вместе формируют аппаратную идентичность, которая сохраняется между сессиями и выживает после стандартных мер конфиденциальности. BotBrowser контролирует все эти сигналы на уровне движка браузера через систему профилей, --bot-time-scale для сжатия интервалов таймингов и --bot-time-seed для пооперационного разнообразия таймингов. Вместе эти флаги обеспечивают внутренне согласованные результаты, соответствующие целевой идентичности устройства. Смежные темы: Canvas fingerprint protection, WebGL fingerprint control и frame rate control.
Похожие статьи
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.