Кроличья нора Facebook*: что браузер помнит, что о себе рассказывает и с кем разговариваетВ мире криптовалют

Кроличья нора Facebook*: что браузер помнит, что о себе рассказывает и с кем разговаривает

Кроличья нора Facebook*: что браузер помнит, что о себе рассказывает и с кем разговаривает

Cookies, хранилища, 3 474 запроса, браузерный отпечаток и WebGPU: технический аудит веб-сессии

С вами Чайка, Head of Innovation в нескольких крупных командах. Мой фокус: искать новые источники трафика и стабилизировать уже работающие. В последний месяц баеры все чаще спрашивают, почему так штормит. Поэтому мы решили заглянуть под капот самого ФБ*: разобраться, как он вас палит и чем это грозит.

Подробнее пишу в своем блоге

В этой статье разберем, что браузер помнит, что хранит и с кем разговаривает, пока вы думаете, что просто смотрите на кабинет. А затем посмотрим, что он рассказывает странице о самом устройстве.

Современный Facebook* это не страница. Это огромное JavaScript-приложение, которое продолжает жить в вашем браузере: читает состояние, создает новое, обращается к локальному хранилищу, ходит в сеть и снова обновляет состояние. Все это без перезагрузки и без единого вашего клика.

Мы продолжили аудит той же веб-сессии с помощью Frida и MITM-прокси. Цифры за одну сессию:

Показатель

Значение

Сетевых запросов

3 474

Сторонних доменов

55

Операций Web Storage (категория DET-050)

1 895

Вызовов IndexedDB

10

Но цифры ничего не значат без ответа на вопрос: что именно за ними стоит? Идем слой за слоем.

Cookie — небольшая запись, которую браузер хранит для сайта и автоматически прикладывает к запросам. Выглядит просто (name=value), но вся сила в атрибутах:

Domain · Path · Expires · Max-Age · Secure · HttpOnly · SameSite

Они определяют, где и когда cookie доступна и куда уйдет. Secure разрешает передачу только по защищенному соединению. HttpOnly закрывает cookie от JavaScript. SameSite управляет отправкой в межсайтовых запросах.

Два канала: JavaScript и заголовки

В нашем аудите Facebook* обращался к cookie сразу несколькими способами. Фиксировался классический , а также методы современного Cookie Store API: get(), getAll(), set() и delete().

Вот что здесь принципиально важно для арбитражника. Если у cookie стоит флаг HttpOnly, JavaScript ее не увидит. Но браузер все равно отправит ее серверу вместе с запросом.

Сервер видит cookie, которых не видит ни скрипт на странице, ни вы, если проверяете только “.

Поэтому «я почистил куки» часто означает «я почистил то, что видно». А полный набор состояния профиля гораздо шире.

Cookies — не единственная память. Приложение само записывает туда данные (setItem), читает (getItem), удаляет (removeItem, clear).

Разница в жизненном цикле. Переживает перезапуск браузера. Привязан к конкретной вкладке и ее сессии. Для сайта это возможность хранить часть состояния не на сервере, а у вас.

1 895 операций

Storage API мы выделили в отдельную категорию DET-050. В одном из разделов записи счетчик дошел до 1 895 операций.

Это не 1 895 разных параметров. Одна и та же запись читается снова и снова: приложение проверило состояние, изменило, прочитало заново, сохранило. Но вывод от этого не слабее: Facebook* работает с локальным хранилищем непрерывно. Его состояние в вашем браузере не декорация, а рабочая часть приложения.

И это ровно то, что нужно помнить при настройке профиля: хранилище не должно быть пустой формальностью.

Для сложных структур у браузера есть IndexedDB. Это полноценная база данных: объекты, индексы, хранилища, асинхронная работа. Приложение может держать в ней локальный кэш, настройки и служебные данные.

В аудите зафиксированы три вызова:

  • indexedDB.open(): открыть или создать базу;
  • indexedDB.deleteDatabase(): удалить базу;
  • indexedDB.databases(): получить список существующих баз.

Всего в этой группе 10 вызовов.

Самый интересный здесь databases(). Он позволяет странице спросить браузер: какие базы у тебя уже есть? Профиль, который живет давно, и профиль, созданный пять минут назад, отвечают на этот вопрос по-разному.

Свежий «стерильный» профиль и профиль с историей выглядят для страницы разными устройствами. Даже если и User-Agent, и Canvas у них идентичны.

После загрузки страницы работа только начинается. JavaScript отправляет запросы, получает ответы, подгружает компоненты, обновляет данные, отправляет результаты ваших действий. Поэтому в одной сессии набегает почти три с половиной тысячи запросов.

Это скрипты, стили, картинки, шрифты, данные интерфейса, аналитика, API-запросы и библиотеки. Часть ресурсов приходит с 55 сторонних доменов: CDN, API, аналитика, хранилища, рекламная инфраструктура.

Для вас здесь два практических вывода:

  1. Важна не цифра, а последовательность. Какой домен, какой endpoint, какой метод, какие заголовки и в какой момент. Один запрос сразу после вашего действия информативнее тысячи автоматически загруженных картинок.
  2. Профиль общается не только с facebook.com*. Все, что вы настроили на уровне прокси, DNS и сетевого стека, видят десятки доменов, а не один.

Accept-CH

Мы уже касались Client Hints в первой части. В сетевом слое они проявляются через заголовок Accept-CH: так сервер сообщает браузеру, какие дополнительные характеристики ему нужны. В аудите фигурировали dpr, sec-ch-prefers-color-scheme, sec-ch-ua-full-version-list, sec-ch-ua-model, sec-ch-ua-platform-version и viewport-width.

Вывод тот же, но с практическим весом: все эти значения должны быть согласованы с вашим User-Agent. Если в UA вы Windows, а sec-ch-ua-platform-version или sec-ch-ua-model рассказывают другую историю, это расхождение, которое создаете вы сами.

Permissions-Policy

В наблюдаемых заголовках присутствовал Permissions-Policy. Через него сайт задает правила: какие возможности браузера доступны странице, а какие встроенным iframe и сторонним компонентам. Сервер не только получает данные от браузера, но и управляет тем, что разным частям страницы разрешено.

Report-To и Reporting-Endpoints

В логах встретились Report-To и Reporting-Endpoints. Это инфраструктура браузерных отчетов: сервер объявляет браузеру адрес, куда тот может отправлять отчеты о событиях (ошибки, нарушения политик и подобное).

По теме...  что происходит, что делать и к чему готовиться

Для нас это еще один пример того же принципа: у браузера есть собственный канал связи с сервером, который работает параллельно с обычными запросами страницы.

Отдельная история: WebRTC. Это технология передачи аудио, видео и данных в реальном времени (звонки, конференции, peer-to-peer). Для установления соединения она работает с сетевой информацией: прежде всего с ICE-кандидатами, то есть возможными маршрутами соединения.

В ходе аудита обращения к WebRTC API зафиксированы. Данные самих ICE-кандидатов мы из анализа исключили. Поэтому мы не называем конкретный IP-адрес, который мог получить Facebook*. Мы фиксируем другое: механизм присутствует в сессии, и страница к нему обращается.

Для арбитражника этого достаточно, чтобы поставить WebRTC в чек-лист. Потому что именно этот механизм исторически работает мимо настроек прокси, и на нем чаще всего ломаются профили, где «IP вроде бы красивый».

По отдельности каждый элемент выглядит рутинным. Cookie — механизм HTTP. и IndexedDB — стандарт. Запросы — основа веба. Но вместе они образуют живой цикл, который повторяется тысячи раз за сессию:

Браузер → локальное состояние → JavaScript → сетевой запрос

   ↑                                                                                  ↓

новое состояние ←←←←←←←←←←←← ответ сервера 

И в этом цикле работает главный принцип всей серии: один параметр почти ничего не значит. Значит комбинация и ее согласованность во времени.

Мы не заглядываем в серверную часть Meta* и не утверждаем, как именно там принимаются решения. Но то, что происходит в браузере, мы видели своими глазами. И из этого следуют вполне конкретные вещи для настройки профиля:

Слой

Что мы увидели

Что проверить в профиле

Cookies

 и Cookie Store API; HttpOnly скрыты от JS, но уходят на сервер

Не чистить «на глаз»; куки должны соответствовать истории профиля, а не копироваться вслепую

Web Storage

1 895 операций в категории DET-050

Хранилище должно сохраняться между запусками и не обнуляться при каждом старте

IndexedDB

open(), deleteDatabase(), databases()

Профиль не должен каждый раз выглядеть как только что созданный

Client Hints

Accept-CH: model, platform-version, full-version-list, dpr, viewport-width

Согласованность с UA, платформой и размером окна

Сеть

3 474 запроса, 55 сторонних доменов

Прокси, DNS, часовой пояс и язык должны рассказывать одну историю

WebRTC

Обращения к API зафиксированы

Режим WebRTC в антидетекте настроен и проверен на утечки

Профиль — это не набор подмененных значений. Это живая система, в которой все должно быть согласовано: железо, сеть, хранилища и поведение.

Но это только половина истории. Вторая половина: что браузер рассказывает о самом себе и о железе, на котором запущен.

Давайте честно: кто из арбитражников за последние годы не мечтал открыть Facebook*, запустить рекламу и просто спокойно работать? Без внезапных проверок, без смены правил игры, без попыток понять, почему вчера всё лилось, а сегодня привычный сценарий уже не работает.

Facebook* остается одним из главных источников рекламного трафика, но предсказуемости в нем с каждым годом меньше. Меняются инструменты, проверки и требования к рекламодателям. Поэтому логичный вопрос: что именно Facebook* видит, когда мы открываем его в браузере?

Обычно разговор сводится к User-Agent, разрешению экрана, языку и часовому поясу. Знакомый набор. Но мы решили заглянуть глубже.

Мы провели технический аудит веб-сессии с помощью Frida и MITM-прокси и зафиксировали, какие механизмы Facebook* задействует прямо во время работы. Аудит одной сессии не раскрывает всю серверную кухню Meta*, но то, что мы увидели на стороне браузера, говорит само за себя. Facebook* интересуется не только названием и версией вашего браузера. Страница обращается к целому набору возможностей устройства, на котором этот браузер запущен.

В ходе аудита зафиксированы обращения к свойствам navigator:

  • userAgent;
  • platform;
  • vendor;
  • language и languages;
  • appVersion и appName;
  • hardwareConcurrency;
  • deviceMemory.

Каждый параметр играет свою роль. userAgent сообщает браузер, версию и совместимость. platform описывает платформу, vendor указывает на производителя браузера. appVersion и appName — исторический багаж, их информативность сегодня невелика.

language и languages выдают основной язык и список предпочитаемых. Это часть описания среды, и Facebook* их запрашивает.

Дальше идут параметры, уже близкие к железу. hardwareConcurrency возвращает число логических процессоров. Это не всегда число физических ядер, но для сравнения профилей достаточно. deviceMemory отдает приблизительную категорию объёма оперативной памяти.

Каждое значение по отдельности выглядит безобидно. Но язык, платформа, версия браузера, число потоков и объем памяти в сумме дают довольно подробный портрет устройства. Именно из таких комбинаций и строится техническая идентификация.

Client Hints — современный механизм, который передает характеристики устройства через HTTP-заголовки. В трафике мы зафиксировали запросы через заголовок Accept-CH, то есть сервер прямо просит у браузера дополнительные данные.

В наблюдениях фигурировали такие параметры:

Параметр

Что означает

dpr

Соотношение пикселей устройства к CSS-пикселям

sec-ch-prefers-color-scheme

Предпочтение светлой или тёмной темы

sec-ch-ua-full-version-list

Бренды и полные версии браузера

sec-ch-ua-model

Модель устройства

sec-ch-ua-platform-version

Версия платформы

viewport-width

Ширина области просмотра

Важный момент: данные о среде уходят не только через JavaScript на странице, но и через заголовки запросов. Профиль браузера — это гораздо больше, чем одна строка User-Agent. Если вы настроили только ее, остальное продолжает говорить за вас.

По теме...  как попасть в топ выдачи с казино продуктом

Canvas — один из самых известных механизмов идентификации. Это HTML-элемент для рисования графики прямо в браузере.

В ходе аудита зафиксирован вызов CanvasRenderingContext2D.getImageData(). В нашей классификации он обозначен как DET-002, и мы зафиксировали два таких события.

Метод читает пиксели из заданной области холста и возвращает массив цвета и прозрачности. А результат отрисовки зависит от браузера, графического стека, операционной системы и драйверов. Одно и то же изображение на разных машинах рендерится с микроразличиями, и по ним среду можно различать.

Facebook* обращался к этому методу, так что Canvas в его арсенале есть.

Есть слой информации, о котором легко забыть. Страница измеряет собственные элементы через getBoundingClientRect(), getClientRects(), offsetWidth и offsetHeight.

Так определяются размеры блоков, видимость контента и реальный размер отрисованного текста, а он зависит от установленных шрифтов и их рендеринга. Поэтому геометрия интерфейса — еще один источник данных о вашей системе, и Facebook* активно к нему обращается.

Если копнуть глубже, выяснится, что браузер умеет работать с графикой не только через Canvas. Есть технология, о которой за пределами разработчиков и специалистов по отпечаткам слышали немногие, — WebGPU.

WebGPU — современный интерфейс для работы с графическим процессором. Он дополняет WebGL и умеет заметно больше: веб-приложения получают прямой доступ к возможностям видеокарты для графики и вычислений.

В ходе аудита зафиксирован вызов requestAdapter(): страница запросила у браузера графический адаптер. А это значит, что она получает сведения о поддерживаемых функциях и лимитах вашего GPU.

Зачем это Facebook*? GPU не абстрактная деталь. Устройство, драйверы, операционная система и реализация браузера определяют, какие графические возможности доступны и как выполняются операции. Поэтому WebGPU дает еще один слой данных о реальном железе.

А теперь главное. Если браузер заявляет «RTX 2080», а WebGPU видит среду без нормального GPU, для антифрода это очень интересное несоответствие. И триггерная галочка в ваш адрес.

Именно поэтому в антидетекте мало закрыть Canvas и WebGL. Графическая подсистема должна быть согласована целиком.

О звуке при разговоре об отпечатках вспоминают реже всего. Но у браузера есть Web Audio API, а его центральный компонент — AudioContext.

Представьте аудиоредактор, работающий прямо в браузере: он генерирует сигналы, пропускает их через фильтры и эффекты, обрабатывает аудиоданные.

В ходе аудита зафиксированы вызовы OfflineAudioContext: страница выполняла звуковые вычисления в фоновом режиме, без единого звука для пользователя. Результат таких вычислений зависит от процессора, системы и реализации браузера, а значит, по нему можно отличить одно устройство от другого.

На данный момент пул аудио-отпечатков, соответствующих Windows, составляет 4096 вариантов. Мы не можем просто сгенерировать случайное значение. Оно должно соответствовать реальному процессору, иначе отпечаток будет распознан как фейковый.

Как сайт понимает, что отпечаток фейк

Начнем с того, что аудио-отпечаток не один. Их пять.

Тот, что вы привыкли видеть и который подменяют в антидетектах, — классический вариант, получивший широкое распространение. Он называется Triangle, по треугольной форме волны. Именно его мы видим на большинстве сайтов проверки отпечатков.

Остальные четыре:

  • Прямой рендеринг волн разных типов (sine, square, sawtooth);
  • BiquadFilterNode: сигнал проходит через фильтр;
  • AnalyserNode: снимается спектр и данные временной области;
  • PannerNode: пространственная обработка звука.

Сайт может применить любой из пяти. Если вы подменили только Triangle, остальные четыре продолжают отдавать реальные значения или значения, которые не согласуются с подмененным. Такое расхождение и выдает антидетект.

В ходе аудита мы зафиксировали вызовы requestAdapter() (WebGPU) и OfflineAudioContext (AudioContext). Facebook* обращается к обоим интерфейсам и использует их для антифрод-проверок. Это логично: соцсети и рекламные платформы борются с мультиаккаунтингом, и им критично отличать реальные устройства от подменённых окружений.

Тут и проявляется главная сложность. Настройки браузера видны и легко меняются, а результаты работы API определяются железом, драйверами и системой. Сайту достаточно выполнить несколько вычислений, чтобы получить характерный след. Если антидетект закрывает Canvas и WebGL, но забывает про аудио и WebGPU, это расхождение становится поводом для срабатывания антифрода.

Подменять нужно всю поверхность целиком, а не несколько знакомых параметров.

Современная веб-сессия — это не название браузера и одна-две настройки профиля. В наблюдаемой среде несколько уровней:

  1. Браузерные свойства: язык, платформа, версия, ресурсы устройства;
  2. HTTP Client Hints: дополнительные характеристики в заголовках;
  3. Canvas: чтение пиксельных данных;
  4. Геометрия интерфейса: размеры и положение элементов;
  5. WebGPU: зафиксирован вызов requestAdapter(), страница получает данные о графических возможностях GPU;
  6. AudioContext: зафиксированы вызовы OfflineAudioContext, страница получает результаты звуковых вычислений.

Каждый механизм по отдельности можно объяснить безобидной причиной. Но вместе они складываются в подробный технический портрет среды. И его несоответствия, например браузер заявляет одно, а железо показывает другое, становятся сигналом для антифрода.

В следующей статье идем еще глубже: Performance API, геометрия DOM, Network Information, Media Capabilities, Pointer/Mouse/Idle API и WebAssembly. Там страница наблюдает уже не только за состоянием, но и за тем, как ведет себя браузер и человек за ним.

Нора продолжается.

Ваш Чайка подписывайтесь на БЛОГ.

Мой контакт в Телеге @chaika_inc.


* — принадлежит компании Meta, признанной экстремистской и запрещенной на территории РФ. 


Источник
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x