Conformance diff
Сравнение вашего парсера/коллектора с эталонным захватом: статусы, порядок заголовков, JA3/JA4, токены.
Diff отвечает на один вопрос: увидит ли anti-fraud-гейт сервера трафик вашего парсера отличным от трафика реального приложения? Передайте ему два захвата — эталонный (reference) от настоящего клиента и исследуемый (subject) от вашего коллектора, парсера или replay-прогона — и он сообщит обо всех измеримых структурных расхождениях: дрейф распределения статусов, сигнатуры порядка HTTP/2-заголовков, порядок и разбиение cookie, JA3/JA4 по каждому SNI, наборы ключей декодированных тел, а также связки «выпуск → использование» токенов с дельтами времени.
Это доведённая до продукта версия ручного цикла сравнения через analyze_traffic.py. Мотивация проста: anti-fraud-гейты редко отклоняют запрос по одному громкому сигналу — они копят тихие. Неправильный порядок заголовков, переставленная пара cookie и слишком быстрое повторное использование токена по отдельности выглядят безобидно; вместе они превращаются в 451. Diff выводит все измерения рядом, чтобы вы могли закрыть их за один раз.
[!NOTE] Этот сценарий предназначен для сравнения трафика систем, которые вы имеете право тестировать. Diff пассивен — он сравнивает два захвата, которые у вас уже есть, и ничего не отправляет ни на какой сервер.
Загрузка эталонного и исследуемого захватов
Сначала импортируйте оба захвата (/docs/ru/capture/importing/):
- Эталон (reference): запись
pcap/pcapng(или HAR) реального приложения, в идеале с TLS keylog, чтобы были доступны JA3/JA4 и расшифрованные тела. - Исследуемый (subject): вывод вашего коллектора — pcap, записанный во время работы вашего парсера, или история replay, захваченная обратно в рабочее пространство (/docs/ru/replay/fingerprints/ описывает управление TLS-отпечатком, которое делает replay сопоставимым).
Обе сессии должны быть доступны в API-лаборатории. Чем полнее импорт (наличие keylog, настроенный пайплайн декодирования), тем больше измерений diff способен охватить.
Запуск diff
Откройте API lab → вкладка Collector → представление Conformance (по умолчанию), затем:
- Выберите захват реального приложения в поле Reference (real app).
- Выберите захват вашего парсера/replay в поле Subject (parser / replay).
- При желании задайте Path filter — подстроку для сопоставления с путями запросов (например,
/catalog/product/card), чтобы ограничить diff одним эндпоинтом. - При желании задайте Join cookie — имя токена, по которому связываются носители и минтеры (например,
__gsac_a-goldapple). Оставьте поле пустым — тогда diff сам определит наиболее частый общий cookie. - Нажмите Run conformance diff.
В том же прогоне для исследуемого захвата оцениваются правила device-identity и отчёт о жизненном цикле токенов; оба результата появляются под секциями diff.
Как читать результаты
Отчёт начинается со списка находок, отсортированного по серьёзности; каждая находка соответствует классу расхождений:
| Находка | Серьёзность | Значение |
|---|---|---|
Status drift: 451 appears N× in subject vs M× in reference | high (для 4xx/5xx), иначе warning | Исследуемый получает статусы, которых нет у эталона; исследуемый с преобладанием 4xx/5xx мгновенно проваливает итерацию. |
Header-order signature differs on METHOD host/path | warning | Самая частая упорядоченная последовательность имён заголовков для эндпоинта различается. |
Cookie order differs on METHOD host/path | warning | Имена cookie идут в другом порядке внутри заголовка Cookie. |
TLS fingerprint differs for SNI (JA4 … vs reference …) | high | Набор JA3 или JA4 для данного SNI не совпадает. |
Join field "X" disagrees in N joined pairs | warning | Заголовок носителя расходится со значением, объявленным в теле запроса-минтера. |
Subject capture conforms to the reference on all measured dimensions | info | Расхождений нет ни по одному измеренному измерению. |
Под находками таблица Status distribution показывает количество по каждому статусу для обеих сторон (строки с дрейфом подсвечены), а TLS per SNI перечисляет каждый хост с бейджем match/drift. Распределение классов отклонений разбивает ответы на такие метки, как accepted, antifraud-reject (451), rate-limited (429) и client-certificate-required (ответ 400, в теле которого называется недостающий клиентский сертификат).
Секции отчёта подробно
Каждая секция сравнивает эталон и исследуемый по ключу эндпоинта (METHOD authority+path) и выводит топ сигнатур с каждой стороны — до 8 образцов на секцию — с вердиктом matches для самой частой записи:
| Секция | Что сравнивает |
|---|---|
| Header-order signatures | Упорядоченные последовательности имён заголовков запроса (в нижнем регистре, псевдозаголовки HTTP/2 с : исключены). |
| Cookie orders | Порядок имён cookie внутри каждого заголовка Cookie, по эндпоинтам. |
| Cookie header counts | Сколько заголовков Cookie несёт каждый запрос — ловит различия в разбиении заголовков. |
| TLS per SNI | Уникальные наборы JA3, JA4 и ALPN по каждому серверному имени; хост совпадает только когда совпадают и набор JA3, и набор JA4. |
| Body keysets | Отсортированные JSON-пути ключей (два уровня вглубь) декодированных тел запросов по эндпоинтам — дрейф формы схемы. |
| Token join | См. ниже. |
Связки токенов и дельты времени
Когда join cookie задан или определён автоматически, diff классифицирует запросы каждой стороны как минтеры (ответ установил cookie через Set-Cookie) или носители (запрос его отправляет), а затем связывает носители с минтерами по точному значению cookie. Блок связки сообщает:
- количество пар joined / unmatched для обеих сторон;
- Δt min/median/p90/max — задержка между выпуском токена и его первым использованием, в секундах. Повторное использование токена через 0,1 с после выпуска, когда реальное приложение ждёт секунды, — это временна́я улика;
- requests before first mint — запросы-носители, предшествующие любому событию выпуска, — трафик без bootstrap, который реальное приложение никогда бы не породило.
Базовый отчёт может также проверять согласованность полей через связку — например, что заголовок plaid-os-version в последующих запросах равен mobileSdk.data.text.AndroidSDK из декодированного тела запроса-минтера.
Типичные исправления по классам расхождений
| Расхождение | Типичное исправление |
|---|---|
| Дрейф статусов в 451/403 | Это симптом, а не причина — проработайте поведенческие строки ниже, затем перемерьте. |
| Сигнатура порядка заголовков различается | Отправляйте заголовки запроса в захваченном порядке; большинство HTTP-стеков по умолчанию сортируют или переставляют их. |
| Порядок cookie различается / разбиение | Сериализуйте cookie в наблюдаемом порядке имён как один заголовок Cookie (или с тем же разбиением, что использует приложение). |
| TLS-отпечаток различается | Подгоните ClientHello — используйте захваченные JA3/JA4 как целевой отпечаток для replay/коллектора (/docs/ru/replay/fingerprints/). |
| Набор ключей тела различается | Приведите JSON-схему декодированного запроса в соответствие: те же ключи, та же вложенность, никаких лишних отладочных полей. |
| Δt связки или запросы до выпуска не те | Воспроизведите последовательность bootstrap и ритм выпуска токенов приложения, вместо того чтобы выпускать и отправлять их подряд. |
[!TIP] Исправьте один класс, перезапустите diff и убедитесь, что его находка исчезла, прежде чем двигаться дальше — список находок служит вашей регрессионной проверкой. Когда каждое измерение соответствует, но комбинированные изменения всё равно отклоняются, переключитесь на представление Probes: оно прогоняет одиночные и парные мутации и помечает накопленные отклонения — мутации, которые принимаются по отдельности, но отклоняются в сочетании.