Профили отпечатков и канарейки
Снимки версионируемых профилей отпечатков и оповещения о дрейфе классов отказа.
Когда целевое приложение выпускает обновление, его клиентская идентичность меняется — новый User-Agent, подросший заголовок версии SDK, перекомпилированный TLS ClientHello. Коллектор, собранный под старую форму, продолжает отправлять старую идентичность и начинает ловить срабатывания антифрод-гейта. Профили отпечатков и проверки-канарейки превращают эту тихую поломку в громкое оповещение: профили снимают слепок идентичности, которую демонстрирует захват (с версионированием), а канарейки периодически проигрывают закреплённый эндпоинт и сигнализируют о любом отклонении от базового класса отказа.
Обе функции живут на вкладке API lab → Collector, в представлении Profiles. Всё хранится в SQLite-базе воркспейса (тот же файл, что и захваты — по умолчанию .traffic-jam/traffic_jam.sqlite3, путь можно переопределить переменной TRAFFIC_JAM_DB_PATH), так что профили и канарейки переживают перезапуски API.
[!NOTE] Канарейки проигрывают реальные запросы против живого эндпоинта. Закрепляйте только эндпоинты систем, которые вам разрешено тестировать, и помните про 10-минутный интервал, если цель чувствительна к rate limit.
Снимок профиля отпечатка
Профиль — это версионируемый снимок клиентской идентичности одного захваченного запроса. Бэкенд извлекает из исходного запроса следующие маркеры:
| Поле | Источник |
|---|---|
headers | Все заголовки запроса, кроме псевдозаголовков HTTP/2 (:method, :path, …), в порядке захвата |
userAgent | Заголовок User-Agent |
appVersion | Заголовок plaid-version, если присутствует |
eventUrlParams | Query-параметры as и p, если присутствуют |
ja3, ja4, alpn, tlsVersion | Поля отпечатка TLS ClientHello запроса |
capturedAt | Метка времени снимка (UTC, RFC 3339) |
Чтобы создать снимок:
- Откройте API lab → Collector → Profiles.
- В разделе Profiles выберите определяющий запрос в пикере Profile source (сначала сессия, затем запрос).
- Введите Profile name — если оставить пустым, по умолчанию возьмётся host (authority) запроса.
- Нажмите Snapshot profile version.
Версионирование идёт по имени: повторный снимок под существующим именем сохраняет version = max(existing) + 1, а не перезаписывает, поэтому список профилей хранит историю того, как эволюционировала идентичность. Каждая строка показывает имя, бейдж vN, захваченную версию приложения (если есть) и дату снимка; иконка корзины удаляет версию.
Закрепление канарейки
Канарейка закрепляет один эндпоинт — пару «захваченная сессия/запрос» — плюс опции replay, воспроизводящие базовый результат, и записывает, как выглядит «норма»: в виде статус-кода и класса отказа.
- В том же представлении Profiles, в разделе Canaries, выберите эндпоинт в пикере Canary endpoint.
- Введите Canary name (например,
product card). - Опционально прикрепите Profile из дропдауна (
name vN), чтобы привязать канарейку к конкретной версии идентичности. - Нажмите Pin canary.
Базовый результат берётся из захваченного ответа: его статус-код, а базовый класс отказа устанавливается в accepted. Подтверждающий тост предлагает сразу прогнать канарейку один раз, чтобы убедиться, что отпечаток всё ещё проходит. Сохранённые опции replay зеркалят ручки интерактивного транспорта replay:
{
"transport": "utls",
"fingerprintProfile": "<profile id>",
"forceHttp1": false,
"clientCertId": "<client cert id>",
"headerOverrides": { "X-Example": "value" },
"body": "optional replacement body"
}
Прогон канарейки выполняет replay с включёнными захваченными чувствительными значениями и заранее принятыми подтверждениями мутаций/назначения, так что запрос воспроизводится точно таким, каким был базовый, — без интерактивных подсказок.
Прогон канарейки и чтение вердикта
Каждая строка канарейки показывает её базовый результат (baseline 200 accepted) и последний прогон в виде бейджа: last run 200 · stable, last run 451 · drift или never run. Нажмите Run now, чтобы выполнить одну проверку по требованию.
Прогон проигрывает закреплённый запрос, классифицирует ответ в класс отказа и сравнивает его с базовым. Дрейф — это любое изменение класса отказа, в любую сторону:
accepted→antifraud-reject: отпечаток устарел; гейт теперь отклоняет то, что раньше принимал. Это и есть тревожный случай.antifraud-reject→accepted: ранее отклоняемый запрос теперь проходит — гейт изменился; перевыставьте базовый результат.- Без изменений: вердикт
stable.
Прогон с дрейфом возвращает вердикт вида drift: accepted → anti-fraud rejection (451), а UI поднимает предупреждающий тост с именем канарейки. Каждый прогон записывается (метка времени, статус, класс отказа, флаг дрейфа, ошибка транспорта, если была); список прогонов хранит самые свежие первыми, с потолком 50 на выборку (слой хранения принимает limit до 200). Удаление канарейки каскадно удаляет её историю прогонов.
Словарь классов отказа — тот же, что используют replay, мутационные пробы и conformance diff:
| Класс | Значение |
|---|---|
(пусто) — accepted | 2xx, не отказ |
transport-error | Сбой соединения/TLS до получения ответа |
client-certificate-required | 400, чьё тело называет недостающий mTLS-сертификат клиента |
unauthorized / forbidden / not-found | 401 / 403 / 404 |
rate-limited | 429 |
antifraud-reject | 451 — антифрод-гейт |
redirect | 3xx (replay никогда не следует редиректам) |
client-error / server-error | прочие 4xx / 5xx |
Запланированные оповещения о дрейфе
Пока приложение открыто, представление Profiles повторно прогоняет каждую закреплённую канарейку с фиксированным интервалом в 10 минут и обновляет историю прогонов. Дрейф, обнаруженный в запланированном прогоне, показывает тот же предупреждающий тост, что и ручной прогон, так что коллектор, сломавшийся между прогонами пайплайна, ловится именно здесь — на уровне отпечатка, — а не позже, в виде необъяснимых сбоев пайплайна данных. Таймер работает только пока воркспейс открыт; фонового демона нет.
[!TIP] Дрейф версии приложения — обычный убийца коллектора. Когда канарейка дрейфует, снимите свежую версию профиля с нового захвата обновлённого приложения, сделайте diff заголовков и JA3/JA4 двух версий профиля и перенесите дельту в свой коллектор. Затем diff /docs/ru/collector/conformance/ может подтвердить, что ваш обновлённый парсер совпадает с новым эталонным захватом.
Где это вписывается
Профили питают транспорт replay — опция канарейки fingerprintProfile выбирает, какую снятую идентичность предъявляет replay (см. /docs/ru/replay/fingerprints/ про управление TLS-отпечатком). Когда канарейка срабатывает, цикл такой: перезахватить обновлённое приложение (/docs/ru/capture/importing/), снять новую версию профиля, перезакрепить или перевыставить базовый результат канарейки и убедиться, что экспортированный коллектор всё ещё соответствует (/docs/ru/collector/conformance/).