Воспроизводимость шумового зерна для повторяемых запусков
Как фиксированное целочисленное шумовое зерно делает вывод Canvas, WebGL, Audio и измерений текста повторяемым между сеансами, перезапусками и запусками в CI, и как это проверить.
BotBrowser Team
Нужна поддерживаемая продуктовая документация?
У этой статьи есть соответствующая страница в центре документации. Используйте docs для каноничного сценария настройки, актуальных флагов и долгосрочной справки.
Статья о флаге --bot-noise-seed, который делает шум Canvas, WebGL, WebGPU, AudioContext, ClientRects и TextRects детерминированным. BotBrowser повторяет вывод рендеринга для одного профиля, сборки и зерна, но зерно не задаёт устройство и не восстанавливает вход в аккаунт.
Краткое резюме
Допустимо целое от 1 до 4294967295, а значение 0 сохраняет настройки профиля. Назначайте каждой идентичности своё зерно и подтверждайте повторяемость перезапуском на чистом каталоге пользовательских данных, а для нового зерна фиксируйте изменение или совпадение.
Содержание руководства
- Почему повторяемые зерна делают запуски сопоставимыми
- Что зерно повторяет и чего не касается
- Назначение зёрен идентичностям без создания связей
- Проверка одного и того же зерна после перезапусков
- Воспроизведение результатов в CI
- Как отличить смену зерна от дрейфа фикстуры
- Что совпавший результат показывает и чего не показывает
Почему повторяемые зерна делают запуски сопоставимыми
Тест отпечатка, который при каждом запуске даёт новый ответ, трудно считать надёжным. Шум отпечатка добавляет небольшие вариации в пиксели Canvas, чтение WebGL, аудиосэмплы и измерения текста, чтобы браузер не выдавал сырой вывод одной машины. Если эта вариация берётся заново при каждом запуске, вы не можете понять, откуда взялось изменение результата: из вашей конфигурации, из тестируемой страницы или из самого шума. Фиксированное шумовое зерно исключает третий вариант. BotBrowser может повторять вывод Canvas, WebGL, аудио и измерения текста для фиксированного профиля, сборки и зерна в контролируемом контексте; он не может сделать этот вывод анонимным и не гарантирует тот же результат при другой сборке, другом профиле или других аргументах.
Шумовое зерно - это одно целое число, которое инициализирует генератор псевдослучайных чисел. Из одного и того же начального значения генератор выдаёт одну и ту же последовательность, поэтому два запуска с одинаковым зерном применяют одну и ту же вариацию к одному и тому же рисунку или измерению, а другое зерно даёт иную, но столь же стабильную вариацию. Вы сами решаете, когда вывод должен повторяться, а когда меняться. О том, как выбирать зёрна для стабильных идентичностей и проверять, что зерно повторяется, см. Детерминированный режим: воспроизводимые отпечатки: там описано, что контролирует зерно и как проверить воспроизводимость.
Фиксированное зерно обычно оправдывают четыре задачи:
- Непрерывность сеанса. Возвращение в сервис через несколько запусков с одним и тем же результатом рендеринга.
- Отдельные стабильные идентичности. Собственный шумовой рисунок для каждого аккаунта, арендатора или тестового пользователя, который не меняется между запусками.
- Сравнение запусков. Исключение шума рендеринга как переменной при сравнении двух сборок, двух страниц или двух профилей.
- Воспроизведение в CI. Восстановление условий прошлого запуска, чтобы упавшее сравнение можно было разобрать, а не угадывать.
Дальнейшие разделы идут за одним зерном: от поверхностей, которых оно касается, через назначение зёрен идентичностям к проверке после перезапуска и записи для CI, а затем к ограничениям, которые стоит указывать в отчёте. Справочные значения взяты из публичной документации по шумовому зерну и справочника флагов командной строки, перечисленных в источниках.
Что зерно повторяет и чего не касается
BotBrowser применяет управляемый шум к Canvas 2D, WebGL, WebGPU, AudioContext, ClientRects и TextRects. Флаг --bot-noise-seed (ENT Tier2) делает этот шум детерминированным. При одном и том же профиле, одной и той же сборке и одних и тех же аргументах запуска фиксированное зерно даёт одинаковое чтение Canvas, одинаковое чтение WebGL и WebGPU, одинаковые аудиосэмплы и одинаковые измерения текста и элементов в каждом сеансе и после каждого перезапуска.
Страница видит эффект при чтении результата. HTMLCanvasElement.toDataURL() возвращает data URL для пикселей, которые сейчас хранит canvas, по умолчанию в формате PNG, если вызывающий код не запросил другой тип, поэтому любая вариация рендеринга сразу видна в возвращённой строке. OfflineAudioContext отрисовывает граф аудиоузлов в буфер без воспроизведения, а страница читает значения сэмплов из этого буфера. Вызовы вроде measureText() и getBoundingClientRect() возвращают числа, а не пиксели, но читаются так же: страница спрашивает, браузер отвечает, и ответ либо совпадает с прошлым, либо нет. Зерно влияет на ответ, а не на вопрос. О том, как аудиовывод становится отпечатком и как проверить согласованность аудио, см. Аудио-отпечатки: как AudioContext отслеживает вас: там объяснено, почему аудио работает как сигнал отслеживания.
Повторяемость привязана к содержимому. Страница, которая рисует одну и ту же сцену с зерном 42 в двух сеансах, читает одни и те же пиксели, а та же сцена с зерном 43 даёт другие пиксели, столь же стабильные. Если сама сцена меняется между запусками, вывод меняется по причинам, не связанным с зерном, поэтому для любого сравнения нужна неизменная сцена. О том, почему один и тот же рисунок отличается на разных устройствах, см. Отпечаток Canvas: как он работает и что помогает: там описано, что измеряет отпечаток Canvas и как проверить стабильность.
Допустимый диапазон - от 1 до 4294967295, наибольшее беззнаковое 32-разрядное целое. Значение 0 сохраняет настройки профиля по умолчанию и не инициализирует генератор, поэтому повторяемость при 0 не гарантируется, и использовать его как базовую линию не стоит. Если повторяемость важна, передавайте положительное целое при каждом запуске и проверяйте, что ваш лаунчер или тестовый фреймворк действительно пробрасывает аргумент: случайный 0 или потерянный аргумент незаметно превращают детерминированную настройку в меняющуюся.
Зерно не определяет, какое устройство выдаётся. Идентичность устройства задаёт профиль: строку user agent, размеры экрана, платформу. Зерно лишь формирует вариацию рендеринга и измерений поверх этих значений. Два сеанса с одним профилем и разными зёрнами разделяют значения профиля и различаются шумом, а зерно не сливает два разных профиля в одну идентичность.
У каждого шумового канала в справочнике флагов есть свой переключатель: --bot-noise-canvas, --bot-noise-webgl-image, --bot-noise-audio-context, --bot-noise-client-rects и --bot-noise-text-rects. Каждый принимает true или false. Зерно определяет, как выглядит шум, а переключатели определяют, какие поверхности его получают, так что эти два параметра отвечают на разные вопросы. Отключение одного канала - полезный диагностический шаг, когда результат перестал повторяться, при условии что вы включите его обратно, прежде чем полагаться на настройку.
Ряд вещей лежит за пределами зерна. Cookie, хранилище и состояние входа находятся в каталоге, заданном --user-data-dir, и зерно не восстанавливает вход в аккаунт. У времени выполнения свой параметр: --bot-time-seed принимает целое от 1 до 4294967295 для воспроизводимой политики времени, а 0 её отключает. Одно шумовое зерно не делает время повторяемым, а зерно времени не меняет вывод Canvas. Если тесту нужна повторяемость и рендеринга, и времени, задайте оба значения осознанно и запишите оба.
Назначение зёрен идентичностям без создания связей
Относитесь к зерну как к конфигурации отдельной идентичности. Профиль с зерном 100 - это один стабильный отпечаток. Тот же профиль с зерном 200 - второй отпечаток со своим шумовым рисунком. Именно поэтому стоит держать по одному зерну на аккаунт, арендатора или тестового пользователя, и именно это позволяет каждой идентичности выдавать тот же результат рендеринга при следующем визите.
Обратный случай - тот, от которого нужно защищаться. Если две идентичности используют один профиль и одно зерно, они дают одинаковый результат рендеринга, и этот общий результат может их связать. Зерно - это конфигурация, а не секрет, предотвращающий корреляцию: любой, у кого есть та же сборка, профиль и зерно, воспроизведёт тот же вывод. Раздельные идентичности защищает то, что никакие две из них не делят и профиль, и зерно.
Храните таблицу соответствия зёрен и идентичностей в системе контроля версий рядом с именами файлов профилей. Каждая строка должна содержать идентичность, имя файла профиля, зерно и дату создания пары.
[
{ "identity": "tenant-a", "profile": "profile-a.enc", "seed": 1001 },
{ "identity": "tenant-b", "profile": "profile-a.enc", "seed": 1002 },
{ "identity": "tenant-c", "profile": "profile-b.enc", "seed": 1003 }
]
В этой таблице арендаторы A и B используют один профиль, но разные зёрна, поэтому их шумовые рисунки различаются. Арендатор C использует другой профиль. Если перенести арендатора B на зерно 1001, две идентичности получат один профиль и одно зерно: этот шаблон нужно фиксировать как риск связывания и исправлять до следующего запуска, назначив одной из них новое зерно.
Создайте каждое зерно один раз и сохраните его. Не выводите зерно из метки времени или из счётчика, который сбрасывается, потому что тогда детерминированная настройка незаметно получит другое значение при каждом запуске. Зерно нельзя восстановить из вывода позже, так что таблица - единственная запись о нём. Подойдёт любое положительное целое из допустимого диапазона, а большие, простые или узорчатые значения никаких преимуществ не дают. Последовательные значения допустимы, если таблица показывает, кому какое принадлежит.
Когда один процесс браузера должен нести несколько идентичностей, пообъектный отпечаток для контекстов (ENT Tier3) позволяет задать каждому BrowserContext собственный --bot-noise-seed. По документации флаги контекста задаются до создания его первой страницы, поэтому рендерер стартует с правильными значениями. Второй контекст с другим зерном даёт другой рисунок, столь же воспроизводимый.
Проверка одного и того же зерна после перезапусков
Приведённая ниже проверка подтверждает, что одно зерно повторяется, а другое меняет вывод. Для неё нужна страница под вашим контролем или тестовая страница, которая каждый раз рисует одну и ту же сцену. Страница должна рисовать фиксированную сцену Canvas и читать её через toDataURL(), читать фиксированную сцену WebGL, отрисовывать фиксированный офлайн-аудиобуфер и измерять фиксированную строку. Записывайте каждое значение или его короткий дайджест, чтобы сравнения были точными. Загружайте страницу каждый раз одинаково, с тем же размером окна и тем же порядком загрузки, чтобы зерно оставалось единственным намеренным отличием между запусками.
Чистый каталог пользовательских данных не пускает в сравнение старое состояние браузера:
chromium-browser \
--bot-profile="path/to/profile.enc" \
--bot-noise-seed=42 \
--user-data-dir="$(mktemp -d)"
Выполняйте проверку в таком порядке:
- Запустите браузер с профилем и
--bot-noise-seed=42, загрузите страницу и запишите значения Canvas, WebGL, Audio и текста. - Закройте браузер, запустите снова с тем же профилем и зерном и загрузите ту же страницу. Каждое записанное значение должно совпасть с первым запуском.
- Смените зерно на 43 и запустите страницу в третий раз. Запишите, отличается ли каждое значение или совпадает с первым: отличие показывает влияние зерна на поверхность, а совпадение показывает, что новое число не гарантирует уникальность.
- Запустите дважды с
--bot-noise-seed=0. Повторяемость при 0 не гарантируется, поэтому не используйте эти значения как базовую линию: 0 не инициализирует генератор. - Сохраните рядом с результатами сборку, файл профиля, операционную систему хоста и полный список аргументов.
Пятый шаг чаще всего пропускают, и именно он объясняет позднее расхождение. Результат сопоставим с другим результатом только тогда, когда совпадают сборка, профиль, зерно и аргументы запуска.
Если второй сеанс не совпал с первым, исключите привычные причины, прежде чем подозревать зерно:
- Сцена изменилась: текст, размер canvas или порядок рисования различаются между запусками.
- Зерно не дошло: лаунчер потерял аргумент или значение равно 0.
- Загружен другой файл профиля или другая версия профиля.
- Использована другая сборка BotBrowser или другая целевая операционная система хоста.
- Фреймворк или обёртка добавили лишние аргументы.
- Один шумовой канал был выключен в одном запуске и оставлен включённым в другом.
Документация даёт тот же совет для настройки, которая ведёт себя иначе на другой машине: сравните сборку BotBrowser, версию профиля, целевую операционную систему хоста и полные аргументы запуска. Она также советует держать стабильными сетевой маршрут, локаль, часовой пояс и нагрузку на машину, пока вы сравниваете запуски, потому что они могут менять поведение страницы, даже когда зерно осталось прежним.
Расхождение - это находка, а не шум, который нужно усреднить. Фиксируйте его как различие сборки, профиля или аргументов, пока не доказано обратное, и сохраняйте оба набора результатов вместе с записями. Перезапуск до случайного совпадения значений скрывает причину и оставляет следующий запуск столь же неопределённым.
Сузить расхождение без догадок
| Шаг | Что сравнить первым | Совпадение здесь означает |
|---|---|---|
| 1 | Полный список аргументов | Зерно и переключатели каналов дошли |
| 2 | Дайджест файла профиля | Загружены те же байты профиля |
| 3 | Строка сборки | Один и тот же бинарник дал оба запуска |
| 4 | Входные данные сцены | Страница дважды нарисовала одно и то же |
Шесть причин выше легко перечислить и трудно разделить, потому что все они дают один симптом: две записи, которые различаются. Проход по четырём входам в этом порядке стоит одного сравнения на шаг и исключает дешёвые объяснения до того, как вы тронете страницу.
Сначала сравните список аргументов, и сравнивайте его как текст, а не по памяти. Лаунчер, потерявший флаг, обёртка, добавившая свой, и оболочка, раскрывшая переменную иначе, оставляют один след: у запуска, давшего расходящиеся значения, никогда не было того зерна, о котором вы думаете. Напечатайте действующие аргументы обоих запусков и сравните их.
Затем сравните файл профиля, по дайджесту, а не по имени. Два файла с одинаковым именем в разных каталогах или файл, заменённый при обновлении профиля, дают расхождение, похожее на проблему зерна, а являющееся проблемой профиля. Сравнение дайджестов превращает это в ответ «да или нет».
Потом строку сборки, целиком, а не только мажорную версию. Младшее обновление внутри того же мажора может изменить путь отрисовки, пока все видимые номера выглядят привычно. Если сборка различается, перестаньте считать две записи сопоставимыми и сохраните обе как отдельные базовые линии.
Только когда эти три совпали, сцену стоит проверять. Сравните размеры холста, текстовую строку, порядок отрисовки и параметры аудиобуфера, потому что любое из них меняет вход, который получает генератор, а значит и выход при том же зерне. Изменение сцены является единственной причиной, при которой зерно работает правильно, а результат всё равно различается.
Чтобы изолировать поверхность, которая перестала повторяться, отключайте по одному каналу, сравнивайте и возвращайте его обратно:
chromium-browser \
--bot-profile="path/to/profile.enc" \
--bot-noise-seed=42 \
--bot-noise-canvas=false
Если остальные поверхности повторяются при выключенном шуме Canvas, значит, меняется сцена Canvas или её чтение. Верните переключатель и сохраните итоговую командную строку в заметках, чтобы те же аргументы можно было вставить в следующий сеанс.
Воспроизведение результатов в CI
Задание CI - это запуск, за которым никто не следит, поэтому ему нужна запись, которую человек иначе держал бы в голове. Зафиксируйте в конфигурации задания сборку BotBrowser, файл профиля, зерно и полные аргументы запуска и выводите их в журнал задания вместе со значениями, которые вернула проверочная страница. Когда сравнение упадёт спустя недели, этот вывод позволит воспроизвести запуск на другой машине, а не гадать.
Полезная запись для каждого зерна содержит несколько полей:
- Значение зерна и идентичность или тестовый случай, к которым оно относится.
- Имя файла профиля и его версия.
- Сборка BotBrowser.
- Целевая операционная система хоста и тип машины.
- Полный список аргументов, включая зерно времени.
- Значения, которые вернула проверочная страница, с датой запуска.
Используйте чистый каталог пользовательских данных для каждого запуска CI, как в команде выше, чтобы старые cookie и хранилище не влияли на сравнение. Держите зерно в конфигурации задания, а не выбирайте его внутри задания: зерно, выбранное во время выполнения, будет другим значением при каждом запуске.
Запускайте проверочную страницу первым шагом задания, до тестов, которые от неё зависят. Если она возвращает значения, совпадающие с сохранённым эталоном, продолжайте. Если значения другие, остановитесь и сообщите, что изменилось: сборка, профиль, зерно или аргументы, вместо того чтобы позволять следующим тестам падать по причине, которую трудно увидеть.
Обновления - второй момент, когда проверку нужно повторить. После обновления BotBrowser, замены файла профиля, перехода на другой раннер или правки аргументов запустите страницу один раз с сохранённым зерном и сравните результат с сохранёнными значениями. Если они совпали, продолжайте. Если различаются, считайте новые значения новым эталоном, запишите сборку, которая их дала, и не правьте зерно, чтобы вернуть прежний вывод: менялось не зерно.
Иногда новый рисунок - это то, что вам нужно, например когда вы выводите из работы тестовую идентичность и заводите другую. Меняйте зерно намеренно, обновляйте таблицу и эталон в одном коммите и оставляйте старую строку с номером сборки. Старое зерно остаётся верным описанием того, что эта сборка выдала для этого профиля.
Повторяемость между машинами и операционными системами подчиняется тому же правилу. Запустите страницу на каждом раннере с одной сборкой, профилем и аргументами и сравните значения. Совпадение служит свидетельством для этих машин. Различие фиксируется как несоответствие сборки, профиля или аргументов, которое нужно проследить, а не игнорировать.
Как отличить смену зерна от дрейфа фикстуры
Повторный запуск является единственным способом отличить смену зерна от изменения фикстуры, и сравнение верно лишь пока сцена, сборка и профиль остаются неизменными. Приведённые измерения получены на одной странице-пробе на одной машине: сборка Chromium 144.0.7559.97, профиль Windows 10, headless-хост Linux, фиксированная отрисовка canvas 220×60, фиксированный clear WebGL 64×64 и фиксированный офлайн-буфер звука. Дайджест содержит первые 32 шестнадцатеричных символа SHA-256 от canvas.toDataURL().
| Зерно | Дайджест canvas | Сопоставление | Что показывает |
|---|---|---|---|
| 42 | fd0881c19451370e66313f61e760c77c | запуск дважды, совпадает | одно зерно повторяется |
| 43 | fd0881c19451370e66313f61e760c77c | совпадает с зёрном 42 | другое зерно может воспроизвести прежний вывод |
| 44 | 06ff31e59678fe4d923a85d73479fe2e | новый вывод | другое зерно может дать новый вывод |
| 45 | 06ff31e59678fe4d923a85d73479fe2e | совпадает с зёрном 44 | коллизия не единична |
| 46 | 5877be94c6969400c80033f0a2f4528d | новый вывод | третий отличный вывод |
| 77 | 8138eccb72cb091408fc684572c3504a | новый вывод | подтверждает, что дайджест зависит от зерна |
| 12345 | 5877be94c6969400c80033f0a2f4528d | совпадает с зёрном 46 | вторая коллизия |
Отсюда следуют два вывода, и оба уже, чем кажутся.
Одно и то же зерно повторяется точно, и это и есть гарантия флага. Но два разных зерна тоже могут дать одинаковый вывод: в этом запуске три из семи зёрен совпали с более ранним выводом. Поэтому смена зерна не является надёжным способом получить другой отпечаток. Считайте зерно входом конечного отображения, а не уникальным идентификатором, и если две сущности не должны делить вывод отрисовки, проверяйте вывод, а не полагайтесь на то, что нового целого числа достаточно.
Тот же запуск оставил без изменений дайджест WebGL, отсчёты звука и ширину текста при всех зёрнах, изменился только дайджест Canvas. Это наблюдение при одной сборке, одном профиле и одном хосте, а не утверждение о том, какие поверхности покрывает флаг на всех платформах; переключатели каналов шума являются отдельными элементами управления, и эта проба их не трогала. Повтор пробы в headful-режиме, с профилем macOS и с включённым каналом шума WebGL покажет, сохраняется ли то же разделение в другом окружении.
Что совпавший результат показывает и чего не показывает
Успешная проверка подтверждает узкое утверждение: данная сборка, профиль и зерно повторили одинаковый вывод Canvas, WebGL, Audio и измерений текста на данной машине, а другое зерно изменило его или совпало на измеренных поверхностях. Она не подтверждает, что тот же результат сохранится на любой машине, после любого обновления и на любой странице. Формулируйте результаты в первой форме, и запись останется точной через месяцы.
Повторяемый отпечаток - это компромисс. Одинаковый вывод при каждом визите даёт непрерывность сеанса, и он же позволяет узнавать повторные визиты как повторные. Фиксированное зерно не делает отпечаток анонимным или уникальным и ничего не говорит о том, как с ним поступит конкретный сайт. Рендеринг - лишь одна группа сигналов. Идентичность устройства из профиля, сетевой маршрут, время и то, что сайт делает с визитом, - отдельные параметры управления.
BotBrowser поддерживает фиксированное целочисленное значение --bot-noise-seed от 1 до 4294967295, которое делает вывод Canvas, WebGL, AudioContext и измерений текста повторяемым для одного профиля между сеансами и перезапусками, так что команды могут сравнивать запуски, воспроизводить результаты CI и держать стабильный эталон рендеринга для каждой идентичности. BotBrowser не может сделать вывод с зерном анонимным или защищённым от собственных проверок сайта, не гарантирует одинаковый результат при другой сборке, другом профиле или других аргументах запуска и не заменяет назначение зёрен по идентичностям, сетевые средства управления и меры на стороне сайта.
Для связанного контекста см. Детерминированный режим, Отпечаток Canvas, Защита аудиоотпечатка и Управление профилями.
Что добавлено по сравнению со справочной страницей
Справочная страница перечисляет параметр зерна, его диапазон и затрагиваемые поверхности. Зафиксируйте профиль, сборку, аргументы запуска и тестовую сцену, сравните два запуска с зерном 42, а затем один запуск с зерном 43. Это метод для выполнения, а не результат, заявленный в статье. При расхождении используйте шаги диагностики выше, чтобы отличить изменение сцены или аргументов от различий профиля, сборки или хоста, прежде чем менять зерно.
Источники
- Документация BotBrowser по воспроизводимости шумового зерна
- Справочник флагов командной строки BotBrowser
- Справочник MDN по HTMLCanvasElement.toDataURL
- Справочник MDN по OfflineAudioContext
Практический итог
Выдавайте зерно один раз на идентичность и храните вместе с профилем, сборкой и полными аргументами запуска. Две идентичности с одним профилем и одним зерном дают один результат и могут быть связаны, поэтому перенос на другое зерно считайте новой идентичностью.
Эта статья входит в руководство: Что такое отпечаток браузера?
Похожие статьи
Детерминированный режим: воспроизводимые отпечатки
ОтпечаткиАудио-отпечатки: как AudioContext отслеживает вас
ОтпечаткиОтпечаток Canvas: как он работает и что помогает
ОтпечаткиГлубина стека JavaScript: сигнал конфиденциальности браузера
Отпечаткиwebgl_debug_renderer_info: что GPU раскрывает страницам
ОтпечаткиСнятие отпечатков WebGPU: следующее поколение отслеживания GPU
Переведите BotBrowser из исследований в продакшн
Используйте эти руководства, чтобы понять модель, а затем перейти к кроссплатформенной валидации, изолированным контекстам и масштабируемому браузерному развертыванию.