Что сообщают navigator.hardwareConcurrency и deviceMemory, насколько они огрублены и почему по ним сайты замечают неправдоподобное устройство.
Две строки на JavaScript позволяют странице примерно понять, насколько мощно ваше устройство: сколько у него логических процессоров и сколько примерно оперативной памяти. По отдельности ни одно число не редкость. Вместе они относят посетителя к классу устройства: бюджетный телефон, офисный ноутбук, рабочая станция. В статье разберём, что означает каждое значение, как браузеры намеренно его размывают и почему главное применение этих чисел — проверка, правдоподобно ли заявленное устройство.
Главное
navigator.hardwareConcurrencyсообщает число логических процессоров, доступных для выполнения потоков, и браузер может назвать число меньше реального.navigator.deviceMemoryсообщает примерный объём ОЗУ в ГиБ, округлённый до степени двойки и ограниченный границами, которые выбирает реализация. Это API из экосистемы Chromium, ждать его в каждом браузере не стоит.- Оба значения по замыслу малоэнтропийные. Вес им придаёт сочетание с размером экрана, GPU и платформой; арифметика — в статье энтропия отпечатка и анонимное множество.
- Лучше всего они работают как проверка согласованности: устройство заявляет в user agent один класс, а здесь сообщает другой — значит, противоречит само себе.
- BrowserInsight показывает оба значения ровно так, как их сообщает ваш браузер, а его проверка на ботов применяет простую проверку диапазона и не сравнивает значения с вашим user agent.
Зачем эти API существуют
Ни один из них не создавался для слежки. Оба позволяют странице подстроиться под устройство, на котором она работает.
hardwareConcurrency нужен, чтобы выбрать размер пула Web Worker. Страница MDN hardwareConcurrency приводит именно такой пример: по одному Worker на каждый заявленный логический процессор. Спецификация W3C Device Memory описывает «сигнал класса устройства», который нужен, чтобы отдавать облегчённую версию сайта слабым устройствам и нормализовать метрики производительности, чтобы долгая задача на слабом устройстве оценивалась иначе, чем на мощном.
hardwareConcurrency: логические процессоры, а не ядра
MDN определяет значение как число логических процессоров, доступных для выполнения потоков на компьютере пользователя, от 1 до числа, потенциально доступного браузеру. Важны две детали:
- Логические, а не физические. Четырёхъядерный процессор с двумя потоками на ядро может сообщить 8. Вы видите не число ядер.
- Возможно, заниженное. MDN указывает, что браузер может назвать меньшее число, чтобы точнее отразить, сколько Worker могут работать одновременно, поэтому это не абсолютное измерение железа. Правила занижения для отдельных браузеров мы не приводим: MDN их не фиксирует, и они меняются; смотрите таблицу совместимости на той странице.
На реальных машинах чаще всего встречаются значения вроде 4, 8, 12 или 16, поэтому одно это число почти ничего не сужает. Значения 2 и 24, конечно, разделяют посетителей, но лишь на очень широкие группы.
deviceMemory: огрублено намеренно
Device Memory API задуман неточным. Согласно спецификации и странице MDN deviceMemory:
- Значение — физическая память, округлённая до степени двойки и выраженная в ГиБ, так что вы получаете 2, 4 или 8, а не «7,6».
- Затем оно ограничивается нижней и верхней границами, которые определяет реализация, чтобы не раскрывать редкие очень малые и очень большие объёмы памяти. Спецификация допускает, что реализации могут менять границы со временем и что для разных типов устройств они различаются. В примере MDN браузер не сообщает меньше 2 и больше 32, получаются 2, 4, 8, 16 или 32. Это иллюстрация, а не универсальное правило.
- Оно доступно только в безопасном контексте (HTTPS).
Сервер может получить то же число и без скриптов — через клиентскую подсказку Sec-CH-Device-Memory. Она включается по согласию: сервер сначала должен отправить Accept-CH: Sec-CH-Device-Memory, а MDN помечает заголовок как экспериментальный. О том, как этот путь соотносится с другими подсказками, см. User-Agent Client Hints.
Поддержка неравномерна. Safari и Firefox не предоставляют deviceMemory, поэтому отсутствие значения там нормально и показывается как «неизвестно», а не как тревожный признак. Но само отсутствие свойства всё же кое-что сообщает странице о движке.
Почему два маленьких числа всё же важны
Возьмите типичное сочетание значений и спросите, у скольких посетителей оно такое же. У многих, и именно поэтому ни одно значение само по себе не годится как идентификатор. Риск появляется, когда они складываются с десятками других сигналов — геометрией экрана, рендерером GPU, платформой: каждый сужает толпу. Арифметика анонимного множества показывает, как складываются несколько малоэнтропийных битов, а руководство по фингерпринтингу перечисляет, где эти два значения стоят среди остальных.
Где они важнее: согласованность
Слабый идентификатор может быть сильным детектором лжи. Значения должны подходить устройству, которым представляется браузер:
- Настольный user agent Windows с 2 логическими процессорами и минимальной ступенью памяти для современной машины необычен, хотя и не невозможен.
- Мобильный user agent с десятками логических процессоров или с объёмом памяти, невозможным для телефона, говорит об эмулируемой или виртуализированной среде.
- User agent iPhone, который ещё и отдаёт
deviceMemory, выглядит странно, потому что WebKit это API не предоставляет. - Сотни «разных» посетителей с одинаковым числом ядер, ступенью памяти и размером экрана выглядят как один образ, клонированный много раз. Это тот самый агрегированный признак, на котором строится обнаружение облачных телефонов.
Ничто из этого не доказательство. Признаки взвешиваются вместе с другими противоречиями — невозможными парами GPU и ОС из статьи несоответствие железа в отпечатке, признаками автоматизации из обнаружения headless-браузеров и общим принципом согласованности отпечатка.
Как с ними обращаются средства приватности
Режимы усиленной защиты заменяют точные значения железа типовыми, чтобы все в группе выглядели одинаково. Например, режим resist-fingerprinting в Firefox подменяет navigator.hardwareConcurrency фиксированным значением; компромиссы, включая редкие сайты, ломающиеся на неожиданном значении, разобраны в статье resist fingerprinting. Цель — увеличить анонимное множество, а не изобразить правдоподобную подделку: случайно выдуманное число может быть таким же приметным, как настоящее. Со стороны заголовков браузер отправляет Sec-CH-Device-Memory только после согласия сервера, а само значение и так грубое.
Что на самом деле делает BrowserInsight
Скажем прямо: BrowserInsight делает две вещи. Проверка отпечатка показывает hardwareConcurrency и deviceMemory ровно так, как их сообщает ваш браузер, и «неизвестно», если API отсутствует. Страница обнаружения ботов выполняет проверку правдоподобия hardware_limit, которая лишь проверяет, попадают ли имеющиеся значения в разумный диапазон (ядра от 1 до 64, память до 64 ГиБ). Она не сравнивает их с вашим user agent или GPU. Весь сбор данных идёт в вашем браузере, на сервер ничего не отправляется.
Частые вопросы
hardwareConcurrency — это число ядер процессора? Нет. Это число логических процессоров, которое может вдвое превышать число физических ядер, а браузер вправе назвать меньшее.
Почему мой deviceMemory никогда не равен 6 или 12? Значение округляется до степени двойки до отправки, поэтому промежуточные объёмы попадают в соседнюю ступень.
Может ли сайт узнать мою память без JavaScript?
Только через клиентскую подсказку Sec-CH-Device-Memory, и только если сервер запросил её через Accept-CH, а ваш браузер её поддерживает.
Достаточно ли этого, чтобы меня отследить? Само по себе нет. Для трекера оно полезно только в сочетании со множеством других сигналов.
Итог
hardwareConcurrency и deviceMemory — намеренно скромные сигналы: грубое число процессоров и округлённая ступень памяти. Их практическая ценность — проверить правдоподобие заявленного устройства и добавить несколько бит к большому отпечатку. Посмотрите, что сообщает ваш браузер, в проверке отпечатка и убедитесь, что остальные настройки рассказывают ту же историю.

