Детект безголового режима в CreepJS: три отдельных вердикта
Один зонд по CreepJS: мягкие сигналы, жёсткие биты и проверки обёрток оцениваются отдельно, поэтому очищенная страница всё равно сообщает процент.
BotBrowser Team
Нужна структурированная документация по теме Отпечатки?
Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.
BotBrowser позволяет воспроизвести авторизованный фикстур того же источника под объявленным профилем и сохранить ограниченную запись того, что страница сообщила о своей среде, но он не может сделать тонкую поверхность толстой, не может превратить восстановленную поверхность в сигнал, который никогда не проверялся, и не может изменить то, как библиотека группирует собственные находки. CreepJS читается здесь по открытому исходному коду, три группы вердикта, которые он вычисляет, воспроизводятся, и фиксируется, сколько стоит один сигнал в каждой группе, сколько мягких сигналов нужно странице, чтобы мягкая группа читалась как безголовая, какие жёсткие биты переживают очистку очевидных, и почему процент одной группы нельзя сравнивать с процентом другой.
Кратко
- CreepJS сообщает безголовый режим тремя отдельными процентами, а не одним:
likeHeadlessпо 16 мягким сигналам,headlessпо 3 жёстким битам и группа обёрток по 5 проверкам. - Рабочий стол с головой и настоящим менеджером окон получает
likeHeadless=0% headless=0% wrapper=0%. - Классический безголовый профиль доходит до
likeHeadless=44% (7/16), тогда как его жёсткая группа остаётся на0%, потому что мягкие сигналы и жёсткие биты измеряют разное. - Драйвер, который выдаёт свой флаг и свой токен, получает
headless=100% (3/3), единственная группа с полным результатом в этом прогоне. - Один сигнал стоит 6% в мягкой группе, 33% в жёсткой и 20% в группе обёрток, поэтому одна и та же находка весит совершенно по-разному.
- Страница, восстановившая объект chrome, плагины, типы MIME, данные user agent и просмотрщик PDF, всё равно сообщает
likeHeadless=13% (2/16), потому что геометрия экрана не тронута. - Задание правдоподобного размера окна снижает это до
likeHeadless=6% (1/16), и последним мягким сигналом остаётся программный рендерер. - Обёртка, которая смещает объект chrome, ломает его runtime и меняет
Function.prototype.toString, получаетwrapper=60% (3/5), а две другие группы остаются нулевыми. - Сигнал
noTaskbarэто просто равенство геометрии, поэтому развёрнутое окно на настоящем рабочем столе тоже его вызывает.
Содержание
- Почему три группы разделены
- Сколько стоит один сигнал в каждой группе
- Какие сигналы переживают очищенную страницу
- Где мягкие сигналы преувеличивают случай
- Запись одного безголового показания
Почему три группы разделены
Детект безголового режима часто описывают как один вопрос с одним ответом, а CreepJS намеренно сообщает три ответа. Группы из одного модуля и измеряют разные виды доказательств:
headed-desktop -> likeHeadless=0% (0/16) headless=0% (0/3) wrapper=0% (0/5)
Первая группа содержит шестнадцать мягких сигналов: нет объекта chrome, нет плагинов, нет типов MIME, пустая платформа client hints, отключённый просмотрщик PDF, экран без панели задач, область просмотра равна экрану, программный рендерер и несколько пробелов в возможностях. Каждый это поверхность, которая выглядит тонкой, и каждая также может быть у законного развёртывания.
Флаг драйвера в этой группе это то же значение, которое читает детектор подмены, когда проверяет, сообщает ли нативная функция всё ещё о себе, и подменённые нативные функции и что видит список toString это фиксирует. Вторая группа содержит три жёстких бита, и они жёсткие в другом смысле: флаг драйвера, токен HeadlessChrome в user agent и тот же токен внутри Worker. Они описывают не тонкую поверхность, а браузер, который сам о себе объявил.
Строка решения, построенная из нескольких групп, оценивается и фильтруется иначе, чем эти три процента, и почему один странный сигнал не выносит вердикт это фиксирует. Третья группа содержит пять проверок обёрток: обнаруживается ли прокси iframe, стоит ли объект chrome в неправдоподобной позиции в порядке ключей window, ведёт ли себя chrome.runtime как настоящий объект, изменён ли Function.prototype.toString, и расходятся ли GPU главного потока и Worker. Они описывают страницу, которая отредактировала свою среду, а не ту, что просто выглядит тонкой.
Три группы, три вида утверждений. Слить их в одно число значит потерять различие между «эта среда минимальна», «этот браузер сказал, что он автоматизирован» и «эта страница отредактировала себя», а эти три случая требуют совершенно разных действий.
Сколько стоит один сигнал в каждой группе
Проценты несравнимы между группами, потому что каждый это доля своего знаменателя. Зонд указывает вес одной находки в каждой:
weight:likeHeadless -> one signal = 6%
weight:headless -> one signal = 33%
weight:wrapper -> one signal = 20%
Один мягкий сигнал сдвигает мягкую группу на шесть пунктов, тогда как один жёсткий бит сдвигает жёсткую на тридцать три. Отчёт, печатающий «44%» и «33%» рядом, приглашает читать их как одну шкалу, а это не так: 44% мягкой группы это семь тонких поверхностей, а 33% жёсткой это один браузер, который объявил о себе.
Мягкой группе к тому же нужно много сигналов, прежде чем она прочтётся как преимущественно безголовая:
likeHeadless:1-of-16 -> 6%
likeHeadless:4-of-16 -> 25%
likeHeadless:8-of-16 -> 50%
likeHeadless:12-of-16 -> 75%
likeHeadless:16-of-16 -> 100%
Половина группы требует восьми тонких поверхностей сразу. Это высокая планка, чтобы пересечь её случайно, и поэтому мягкий процент описывает, насколько минимальна среда, а не вероятность того, что она безголовая.
Строка сравнения говорит то же с другой стороны:
compare -> all-16-soft=100% vs one-hard=33% (groups are reported separately)
Страница со всеми шестнадцатью мягкими сигналами читается как 100% в своей группе, а страница с одним жёстким битом как 33% в своей. Ни одно не больше в сколько-нибудь осмысленном смысле, потому что они отвечают на разные вопросы. Кто сортирует два процента, сортирует две разные единицы.
Какие сигналы переживают очищенную страницу
Интересно то, что происходит, когда страница приводит в порядок очевидные сигналы. Зонд подаёт состояние, где объект chrome, плагины, типы MIME, платформа client hints и просмотрщик PDF восстановлены, а геометрия экрана осталась как была:
cleaned-obvious-tells -> likeHeadless=13% (2/16) headless=0% (0/3) wrapper=0% (0/5)
cleaned-plus-window -> likeHeadless=6% (1/16) headless=0% (0/3) wrapper=0% (0/5)
Восстановление пяти поверхностей всё ещё оставляет тринадцать процентов, потому что два сигнала геометрии никто не трогал. Задание правдоподобного размера окна снижает это до шести, и последним мягким сигналом остаётся программный рендерер. Жёсткая группа и группа обёрток всё время на нуле, и это полезная часть: очистка поверхностей не создаёт находок обёрток, она только убирает мягкие.
Эта асимметрия важна для того, кто читает отчёт после изменения. Страница, ушедшая с сорока четырёх на шесть процентов, не стала более или менее безголовой; она стала менее минимальной. Жёсткая группа, та самая, что описывает браузер, объявивший о себе, вообще не сдвинулась, и кто смотрит только на итог, решит, что что-то улучшилось, хотя лежащее в основе утверждение не изменилось.
Обратное тоже верно. Группа обёрток может вырасти без единого мягкого сигнала:
wrapper-wrapped -> likeHeadless=0% (0/16) headless=0% (0/3) wrapper=60% (3/5)
Страница, которая держит каждую поверхность толстой, но смещает объект chrome, ломает его runtime и меняет Function.prototype.toString, получает шестьдесят процентов в группе обёрток, тогда как две другие пусты. Это совершенно иная находка, чем тонкая среда, и она видна только потому, что группы разделены.
Где мягкие сигналы преувеличивают случай
Несколько мягких сигналов это обычные условия, которые законное развёртывание тоже создаёт, и зонд фиксирует два из них.
Сигнал прав требует согласия двух независимых условий:
permissions-bug -> prompt+denied=true prompt+default=false granted+denied=false
Он срабатывает только когда запрос прав сообщает prompt, а разрешение на уведомления равно denied. Ни одно из условий само по себе его не вызывает, и это намеренное сужение: браузер, который просто запрещает уведомления политикой, не помечается, и только несогласованная пара даёт срабатывание.
Сигнал панели задач это противоположный случай, и он самый слабый в группе:
no-taskbar -> 1080/1080+1920/1920=true 1080/1040+1920/1920=false
Это просто равенство между экраном и его доступной областью, поэтому любое развёрнутое окно на настоящем рабочем столе со скрытой панелью его вызывает, как и киоск или полноэкранное устройство. Один пункт мягкой группы сам по себе стоит немного, а этот стоит даже меньше, чем намекают его шесть процентов.
Урок для развёртывания о том, на какие поверхности тратить усилия. Восстановление плагинов и типов MIME двигает мягкую группу, но геометрия и имя рендерера это то, что остаётся после приведения в порядок всего остального. Профиль, который верно делает лёгкие поверхности и не трогает геометрию, читается как шесть процентов мягких, и кто не знает размеров групп, прочтёт это как «почти ничего», хотя на деле это один конкретный сигнал.
Запись одного безголового показания
Безголовое показание подтверждает узкое утверждение: эта версия библиотеки, эти состояния сигналов дали эти три процента. Четыре поля держат его проверяемым:
- Коммит библиотеки и три списка сигналов, потому что список, получивший или потерявший ключ, меняет каждый процент без всякого изменения на странице.
- Имена сработавших сигналов по группам, потому что шесть и тридцать три процента описывают разные виды доказательств, а число скрывает какие.
- Знаменатели каждой группы, потому что сравнивающий мягкий процент с жёстким сравнивает две разные единицы.
- Сигналы, которые не оценивались, потому что нескольким нужна живая страница, а статическое воспроизведение подаёт их как входные данные.
Публичные источники
- CreepJS
- Модуль детекта безголового режима CreepJS
- MDN: Navigator.webdriver
- MDN: Navigator.plugins
- MDN: API разрешений
- BotBrowser: справочник согласованности автоматизации
Практический вывод
Читайте три процента как три отдельные находки, а не как одну оценку, потому что мягкий процент описывает, насколько минимальна среда, жёсткий описывает браузер, объявивший о себе, а процент обёрток описывает страницу, отредактировавшую себя. Воспринимайте падение с сорока четырёх до шести процентов как изменение того, сколько среды раскрыто, а не того, безголовый ли браузер, поскольку жёсткая группа не сдвинулась. Когда отчёт показывает рост одной группы при пустых остальных, ищите проверки обёрток, а не отсутствующие поверхности. О том, как библиотека сворачивает результаты групп в одно упорядоченное решение, читайте группы сигналов CreepJS и их объединение; о том, что может увидеть одна проверка исходного текста, читайте подменённые нативные функции и что видит список toString.
Эта статья входит в руководство: Что такое отпечаток браузера?
Похожие статьи
Группы сигналов CreepJS и как он их объединяет
ОтпечаткиКак читать сигналы отпечатка браузера
ОтпечаткиПочему один странный сигнал не выносит вердикт
ОтпечаткиBotD: какие детекторы действительно выполняются
ОтпечаткиЧто на самом деле проверяют публичные наборы тестов
ОтпечаткиИсточник случайности в crypto-js: ветка сборки
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.