Назад к блогу
Отпечатки

Контроль числа ядер CPU с помощью BotBrowser

Как navigator.hardwareConcurrency раскрывает идентичность CPU для fingerprinting и как BotBrowser управляет отчетом числа ядер во всех контекстах.

Введение

Свойство navigator.hardwareConcurrency возвращает число логических ядер CPU, доступных браузеру. Оно было создано, чтобы помочь веб-приложениям оптимизировать параллельные задачи, позволяя JavaScript решать, сколько Web Worker создавать или как разбивать задачи обработки данных. Но это же свойство раскрывает информацию о железе, которая используется для браузерного fingerprinting. Устройство с 6 логическими ядрами существенно реже, чем устройство с 8, а сервер с 64 ядрами сразу выделяется. Поскольку число ядер стабильно, легко доступно и варьируется в зависимости от конфигурации железа, оно стало стандартным компонентом систем трекинга. В этой статье объясняется, как число ядер влияет на fingerprinting, почему простые переопределения проблематичны и как BotBrowser обеспечивает согласованный отчет числа ядер через систему профилей.

Влияние на приватность

Число ядер может казаться малозначимой сигнатурой, но его вклад значителен в контексте. Ценность любого атрибута fingerprint зависит от его распределения в популяции. По данным проекта AmIUnique, navigator.hardwareConcurrency имеет примерно 4.5 бита энтропии, то есть может различать около 23 групп. Хотя 23 группы — не очень много, каждая дополнительная битовая единица энтропии примерно удваивает идентифицирующую силу при комбинировании с другими сигналами.

Распределение сильно скошено. Значения 4 и 8 составляют большинство десктоп-браузеров. Значения 2 (старые машины, бюджетные Chromebook), 6 (некоторые Intel), 12 (Ryzen 5), 16 (высококлассные десктопы) и выше становятся всё реже. Машина, сообщающая 24, 32 или 64 ядра, почти наверняка является сервером или рабочей станцией — это крайне редко встречается среди обычных пользователей.

Мобильные устройства добавляют дополнительные дифференциаторы. Большинство телефонов сообщает 4 или 8 ядер, но конкретные семейства SoC (Snapdragon, Exynos, MediaTek, Apple Silicon) связывают специфические числа ядер с другими узнаваемыми свойствами. Телефон с hardwareConcurrency равным 8 в сочетании с определённым user agent сокращает количество возможных моделей до нескольких.

Проблема приватности усиливается тем, что hardwareConcurrency доступен во всех контекстах выполнения: главный поток, dedicated workers, shared workers и service workers. Для доступа не требуется никаких разрешений, и его нельзя просто отключить без ущерба для корректной работы легитимных веб-приложений, использующих его для оптимизации производительности.

Технические детали

Как работает hardwareConcurrency

Свойство navigator.hardwareConcurrency возвращает беззнаковое целое число, представляющее количество логических процессоров. "Логические процессоры" означают физические ядра, умноженные на количество потоков на ядро (например, 4‑ядерный CPU с hyperthreading покажет 8).

console.log(navigator.hardwareConcurrency); // например, 8

Значение доступно и в контексте воркеров:

// Внутри Web Worker
console.log(self.navigator.hardwareConcurrency); // то же значение

Почему значение варьируется

Несколько факторов определяют, что возвращает hardwareConcurrency:

  • Физическое оборудование. Число ядер и потоков определяется моделью процессора. Intel i5 часто имеет 4–6 ядер с hyperthreading. AMD Ryzen 7 обычно имеет 8 ядер с SMT. Чипы Apple M имеют разные числа ядер в кластерах энергоэффективности и производительности.
  • Виртуализация. Виртуальные машины сообщают количество выделенных vCPU, которое может отличаться от хоста. VM с 2 vCPU покажет 2.
  • Планирование ОС. Некоторые ОС или контейнерные окружения позволяют ограничить видимое количество процессоров.
  • Реализация браузера. Большинство браузеров возвращают значение, полученное от ОС. Некоторые проекты экспериментировали с ограничением или группировкой значений, но Chromium обычно возвращает реальное число.

Корреляция с другими сигналами

Число ядер не существует в вакууме. Системы трекинга сверяют его с:

  • navigator.deviceMemory — 2 ядра и 8 ГБ RAM выглядят правдоподобно; 2 ядра и 0.25 ГБ — нет.
  • navigator.platform — «Linux x86_64» и 4 ядра указывает на конкретный набор оборудования; «Linux armv81» и 8 ядер может означать ARM сервер или телефон.
  • User agent. Версия браузера и ОС ограничивает, какие числа ядер реалистичны.
  • Тайминги производительности. Реальная параллельная производительность (измеренная таймингами) может сравниваться с заявленным числом ядер.

Несоответствие между заявленным числом ядер и наблюдаемой производительностью — сильный сигнал подмены.

Обычные подходы защиты и их ограничения

Ручное переопределение hardwareConcurrency через расширение или инъекцию JS — самый распространённый подход. Это меняет возвращаемое значение, но создаёт проблемы:

  1. Несоответствие производительности. Если вы сообщаете 4 ядра, но реальная машина имеет 16, параллельные задачи будут выполняться быстрее, чем на реальном 4‑ядерном устройстве.
  2. Детектирование через прототип. JS‑переопределения могут быть обнаружены при проверке дескриптора свойства, цепочки прототипов или измерении времени работы геттера.
  3. Пробелы в воркерах. Некоторые решения меняют только navigator в главном потоке, не патчат воркеры.

Рандомизация значения даёт нереалистичные конфигурации — например, 7 или 13 не соответствуют реальным архитектурам.

Фиксация на общем значении (всегда сообщать 8) лучше, чем рандом, но всё равно рискованно, если это противоречит другим сигналам (user agent телефона, рассчитанного на 4 ядра).

Требование: заявленное число ядер должно быть внутренне согласовано с другими свойствами устройства и не противоречить наблюдаемой производительности.

Подход BotBrowser на уровне движка

BotBrowser контролирует navigator.hardwareConcurrency на уровне движка Chromium через систему профилей. Такой подход имеет преимущества по сравнению с JS‑уровнем.

Значения, основанные на профиле

Каждый профиль fingerprint BotBrowser указывает значение hardwareConcurrency, соответствующее реальной конфигурации целевого устройства. Профиль Windows 10 desktop с Intel i7 вернёт 8 или 16 ядер. Профиль Android со Snapdragon 888 — 8 ядер. Значения берутся из реальных конфигураций, а не генерируются случайно.

Согласованность во всех контекстах

Поскольку контроль выполняется на уровне движка, все контексты возвращают одинаковое значение:

  • Главный поток navigator.hardwareConcurrency
  • Dedicated Worker self.navigator.hardwareConcurrency
  • Shared Worker self.navigator.hardwareConcurrency
  • Service Worker self.navigator.hardwareConcurrency

Нет пробелов, где один контекст показывает реальное значение, а другой — профильное.

Согласованность с другими сигналами

Значение hardwareConcurrency в профиле является частью полной идентичности устройства. Оно согласовано с:

  • User agent и платформой
  • Значением deviceMemory
  • Разрешением экрана и другими аппаратными сигналами
  • Брендом и версией браузера

Это предотвращает выявление несогласованностей при перекрёстных проверках.

Отсутствие артефактов на уровне JavaScript

Поскольку значение задаётся в движке, отсутствуют изменённые дескрипторы свойств, ненативные геттеры или измеримые временные различия. Свойство ведёт себя так, как на профилируемом оборудовании.

Конфигурация и использование

Базовая загрузка профиля

chrome --bot-profile="/path/to/profile.enc" \
       --user-data-dir="$(mktemp -d)"

Профиль автоматически определяет, какое число ядер будет показано.

Проверка значения

// В консоли браузера или в автоматизационном скрипте
console.log(navigator.hardwareConcurrency);
// Возвращает значение профиля, а не реального оборудования

Интеграция с Playwright

const { chromium } = require('playwright');

const browser = await chromium.launch({
  executablePath: '/path/to/botbrowser/chrome',
  args: [
    '--bot-profile=/path/to/profile.enc'
  ]
});

const page = await browser.newPage();
await page.goto('https://example.com');

const cores = await page.evaluate(() => navigator.hardwareConcurrency);
console.log(`Reported cores: ${cores}`);

// Проверка совпадения в воркере
const workerCores = await page.evaluate(() => {
  return new Promise(resolve => {
    const blob = new Blob([
      'postMessage(self.navigator.hardwareConcurrency)'
    ], { type: 'application/javascript' });
    const worker = new Worker(URL.createObjectURL(blob));
    worker.onmessage = e => resolve(e.data);
  });
});
console.log(`Worker cores: ${workerCores}`);

Интеграция Puppeteer

const puppeteer = require('puppeteer');

const browser = await puppeteer.launch({
  executablePath: '/path/to/botbrowser/chrome',
  defaultViewport: null,
  args: [
    '--bot-profile=/path/to/profile.enc'
  ]
});

const page = await browser.newPage();
await page.goto('https://example.com');

const cores = await page.evaluate(() => navigator.hardwareConcurrency);
console.log(`Reported cores: ${cores}`);

Проверка

Проверка значения. Запросите navigator.hardwareConcurrency и убедитесь, что он соответствует ожидаемому значению профиля.

Согласованность в воркерах. Создайте Web Worker и проверьте self.navigator.hardwareConcurrency внутри — значение должно совпадать с главным потоком.

Кросс‑проверка свойств. Убедитесь, что число ядер правдоподобно для платформы, user agent и deviceMemory профиля.

Стабильность между сессиями. Значение должно быть идентично при повторных запусках с тем же профилем.

Лучшие практики

  • Используйте полный профиль. Не пытайтесь менять только hardwareConcurrency изолированно.
  • Выбирайте реалистичные профили. Частые значения (4, 8) выглядят естественно; необычные (6, 12, 24) привлекают внимание.
  • Тестируйте в воркерах. Всегда проверяйте, что воркеры возвращают то же значение, что и главный поток.
  • Избегайте ручных переопределений. Профили BotBrowser спроектированы для внутренней согласованности; ручные изменения создают обнаружимые расхождения.

FAQ

Q: Какие значения hardwareConcurrency наиболее распространены? A: На десктопе 4 и 8 наиболее часты (>70%). На мобильных устройствах также преобладают 4 и 8. Значения 2, 6, 10, 12, 16 и выше встречаются реже.

Q: Может ли сайт измерить реальное число ядер независимо от hardwareConcurrency? A: Теоретически — да, через SharedArrayBuffer и высокоточные таймеры, но практические ограничения (снижение точности таймеров, требования COOP/COEP) затрудняют это. Контроль на уровне движка в BotBrowser повышает согласованность.

Q: Меняется ли hardwareConcurrency при обновлении браузера? A: Нет. Это отражение конфигурации железа/ОС, а не версии браузера.

Q: Доступен ли navigator.hardwareConcurrency во всех браузерах? A: Да. Основные браузеры (Chrome, Firefox, Safari, Edge) поддерживают свойство.

Q: Почему некоторые VM показывают значение, отличное от хоста? A: VM видит только vCPU, назначенные гипервизором; хост может иметь больше ядер.

Q: Влияет ли число ядер на производительность Web Workers в BotBrowser? A: BotBrowser управляет только сообщаемым значением; реальная планировка использует физическое оборудование. Значение влияет лишь на то, что видит JavaScript.

Резюме

navigator.hardwareConcurrency — простое свойство, возвращающее одно число, но оно существенно влияет на fingerprinting в сочетании с другими сигналами. BotBrowser контролирует это значение на уровне движка через профили, обеспечивая согласованность во всех контекстах и согласование с остальными сигналами идентичности.

Для смежных тем смотрите What is Browser Fingerprinting, Navigator Property Protection и Deterministic Browser Behavior.

title: "Управление количеством ядер CPU с BotBrowser" description: "Как BotBrowser контролирует navigator.hardwareConcurrency через профили отпечатков для согласованного отчета о ядрах CPU во всех контекстах." date: "2025-05-14" locale: ru category: fingerprint tags: ["cpu", "cores", "hardwareConcurrency", "fingerprinting", "privacy"] published: true

Риск для конфиденциальности

navigator.hardwareConcurrency возвращает количество логических ядер процессора, доступных браузеру. Это значение является сигналом отслеживания, поскольку раскрывает класс устройства: сервер, настольный компьютер, ноутбук или мобильное устройство. Не требует разрешений и доступно из основного потока, Web Workers и iframe.

Решение BotBrowser

BotBrowser устанавливает количество ядер из профиля отпечатка на уровне движка браузера, до выполнения любого JavaScript. Значение согласовано во всех контекстах выполнения.

Загрузка профиля

chrome --bot-profile="/profiles/windows-chrome-122.enc" \
       --user-data-dir="$(mktemp -d)"

Если профиль был снят с 8-ядерного настольного компьютера, navigator.hardwareConcurrency вернет 8 независимо от того, имеет ли хост-машина 2 ядра или 96 ядер.

Все контексты совпадают

Количество ядер профиля применяется к:

  • navigator.hardwareConcurrency основной страницы
  • Контекстам Web Worker и SharedWorker
  • Контекстам Service Worker
  • Объектам navigator в iframe

Серверная автоматизация

При запуске на облачном сервере количество ядер хоста раскрывает серверную среду. BotBrowser представляет количество ядер потребительского устройства из профиля:

const { chromium } = require('playwright-core');

const browser = await chromium.launch({
  executablePath: '/path/to/botbrowser/chrome',
  args: [
    '--bot-profile=/profiles/windows-chrome-122.enc',
  ],
  headless: true,
});

const page = await (await browser.newContext()).newPage();
const cores = await page.evaluate(() => navigator.hardwareConcurrency);
console.log('Сообщаемые ядра:', cores); // 8, не 96

Верификация

Проверьте согласованность количества ядер между контекстами:

const page = await (await browser.newContext()).newPage();

const mainCores = await page.evaluate(() => navigator.hardwareConcurrency);

const workerCores = await page.evaluate(() => {
  return new Promise(resolve => {
    const blob = new Blob([
      'self.postMessage(navigator.hardwareConcurrency)'
    ], { type: 'application/javascript' });
    const w = new Worker(URL.createObjectURL(blob));
    w.onmessage = e => resolve(e.data);
  });
});

console.log('Основной поток:', mainCores);
console.log('Web Worker:', workerCores);
console.log('Совпадение:', mainCores === workerCores);

Оба значения должны совпадать с записанным в профиле количеством ядер, а не с реальным количеством ядер хост-машины.

Начало работы

  1. Скачайте BotBrowser с GitHub
  2. Выберите профиль из репозитория профилей
  3. Запустите с --bot-profile для применения полной аппаратной идентичности
  4. Проверьте с помощью navigator.hardwareConcurrency в консоли браузера
#cpu#fingerprinting#hardwareConcurrency#privacy