← Назад в базу знаний

Как антифрод-системы маркетплейсов палят мультиаккаунты по корреляции часовых поясов и языка браузера

Как антифрод-системы маркетплейсов палят мультиаккаунты по корреляции часовых поясов и языка браузера

Что вообще видят антифрод-системы

Мультиаккаунт палится не по одному признаку. Никогда. Антифрод маркетплейса — это граф связей, где каждая сессия оставляет десятки узлов: IP, ASN, часовой пояс, язык, шрифты, WebGL, canvas-хеш, поведение мыши, время между действиями. Задача системы — не найти "плохого", а построить кластеры, где аккаунты подозрительно похожи.

Часовой пояс и язык браузера — два самых дешёвых сигнала. Их собирают первыми. Они не требуют ни капчи, ни отпечатка железа, ни анализа поведения. Просто JS-скрипт при загрузке страницы читает `Intl.DateTimeFormat().resolvedOptions().timeZone`, `navigator.language`, `navigator.languages` и отправляет на сервер. Всё. Дальше — статистика.

Именно поэтому корреляция этих двух полей даёт антифроду больше, чем полный canvas-фингерпринт. Потому что их сложно подделать одновременно с IP, и потому что они меняются редко — пользователь не переключает таймзону каждые пять минут.

Как работает связка TZ + IP

Сервер видит два независимых источника: IP-адрес (откуда пришёл запрос) и часовой пояс (что заявил браузер). Если IP резолвится в Германию, а `timeZone` — `Asia/Novosibirsk`, это флаг. Одиночный — слабый. Систематический — сильный.

Антифрод берёт гео-базу (MaxMind, IP2Location, собственные данные) и сопоставляет: какой таймзон ожидается для этого IP. Допустим, диапазон `185.220.x.x` — это Hetzner, Германия. Ожидаемая таймзона: `Europe/Berlin`. Браузер говорит `Europe/Moscow`. Расхождение. Одно очко в копилку подозрительности.

Но это ещё не приговор. Реальный пользователь может сидеть под VPN. Поэтому система смотрит на корреляцию: если 8 из 10 аккаунтов, заходящих с немецких IP, заявляют московскую таймзону — это уже кластер. Антифрод связывает их в один граф и помечает.

Что именно собирает JS

Стандартный фингерпринт-скрипт на маркетплейсе собирает примерно такой набор:

```javascript

const fp = {

timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,

tzOffset: new Date().getTimezoneOffset(),

language: navigator.language,

languages: navigator.languages,

locale: Intl.DateTimeFormat().resolvedOptions().locale,

currency: Intl.NumberFormat().resolvedOptions().currency,

dateFormat: new Intl.DateTimeFormat().format(new Date()),

numberFormat: new Intl.NumberFormat().format(1234567.89)

};

```

Обрати внимание на последние три. `dateFormat` для `en-US` даст `12/25/2024`, для `ru-RU` — `25.12.2024`. `numberFormat` для `de-DE` вернёт `1.234.567,89`, для `en-US` — `1,234,567.89`. Это косвенные подтверждения локали, которые не подделать простым переключением `navigator.language`.

Антифрод сравнивает: если `navigator.language` = `ru-RU`, но `dateFormat` показывает американский порядок — значит, язык выставлен вручную, а система осталась дефолтной. Классический след автоматизации или неаккуратной подмены.

Расхождение языка и таймзоны — главный маркер

Самая частая ошибка мультиаккаунтера — выставить русский язык, но забыть про таймзону. Или наоборот: поставить таймзону США, но оставить `ru-RU` в браузере.

Пример: сервер за прокси в Вирджинии, IP принадлежит DigitalOcean (`159.89.x.x`), ожидаемая таймзона `America/New_York`. Браузер заявляет `Europe/Moscow` и `ru-RU`. Три сигнала противоречат друг другу: IP говорит "США", таймзона — "Россия", язык — "Россия". Антифрод видит несоответствие IP↔TZ и записывает в профиль вес.

Дальше система проверяет историю. Если этот же fingerprint (или его варианты) появлялся на других аккаунтах — связь установлена. Даже если IP каждый раз новый. Потому что TZ + язык + формат даты + разрешение экрана + список шрифтов дают устойчивый кластер.

Как это выглядит в логах антифрода

Реальный пример структуры события, которое отправляется на бэкенд маркетплейса при логине:

```json

{

"session_id": "a7f3e9c2...",

"ip": "159.89.44.12",

"asn": "AS14061 DigitalOcean",

"geo_country": "US",

"geo_city": "Clifton",

"tz": "Europe/Moscow",

"tz_offset": -180,

"lang": "ru-RU",

"langs": ["ru-RU", "ru", "en-US", "en"],

"screen": "1920x1080",

"color_depth": 24,

"canvas_hash": "8f2a...",

"webgl_vendor": "Google Inc. (NVIDIA)",

"fonts_hash": "3c91...",

"login_ts": 1703421600

}

```

Антифрод-движок прогоняет это через правила. Одно из базовых: `geo_country != tz_country`. Если `US` против `Europe/Moscow` — вес +15. Если таких сессий с одного ASN больше десяти за сутки — вес +40. Если `canvas_hash` повторяется на разных аккаунтах — вес +60 и ручная проверка.

Порог срабатывания обычно 100-150 очков. Набирается быстро, если не следить за консистентностью.

Почему подмена TZ через DevTools не спасает

Многие думают: открою DevTools, переопределю `Intl.DateTimeFormat`, и всё. Не работает по двум причинам.

Первая: антифрод читает таймзону не только через JS. Он смотрит на HTTP-заголовки, на TLS-фингерпринт (JA3/JA4), на порядок заголовков. Некоторые системы используют `Date` header от клиента и сравнивают с серверным временем. Если клиент шлёт время в UTC+3, а IP в UTC-5 — расхождение видно без всякого JS.

Вторая: если ты переопределяешь `Intl` через прокси-объект, это ломает другие вызовы. `toLocaleString()` начинает возвращать не то, что ожидает страница. Маркетплейс может отправить тестовый вызов: создать дату и отформатировать её для известной локали, потом проверить результат. Подмена палится на несоответствии.

Вот пример теста, который может прогнать антифрод:

```javascript

const test = new Date('2024-06-15T12:00:00Z');

const expected = {

'Europe/Moscow': '15.06.2024, 15:00:00',

'America/New_York': '6/15/2024, 8:00:00 AM'

};

const actual = test.toLocaleString(navigator.language, {

timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone

});

```

Если `actual` не совпадает с ожидаемым для заявленной таймзоны — значит, что-то подменено. Скрипт помечает сессию.

Связка с поведенческими метриками

TZ и язык — статические сигналы. Их дополняют динамические. Антифрод смотрит на время активности: когда аккаунт заходит, когда совершает действия. Если таймзона заявлена как `America/Los_Angeles`, но все действия происходят с 9:00 до 18:00 по Москве — это несоответствие.

Пример: аккаунт с TZ `America/Chicago` логинится каждый день в 02:00 по местному времени (что соответствует 11:00 МСК). Активность идёт ровно 8 часов. Потом оффлайн. Для Чикаго это ночная смена, для Москвы — рабочий день. Антифрод складывает: TZ + паттерн активности + IP из дата-центра = автоматизированный мультиаккаунт.

Плюс скорость действий. Человек не может заполнить форму регистрации за 4 секунды. Бот может. Если время между загрузкой страницы и сабмитом меньше 6 секунд — вес растёт.

Кейс: сеть аккаунтов на одном прокси-пуле

Маркетплейс электроники, 40 аккаунтов, все заходят через пул из 12 прокси в Нидерландах. IP разные, ASN один — `AS49981 WorldStream`. Таймзона у всех `Europe/Amsterdam`, язык `nl-NL`. На первый взгляд — консистентно.

Но антифрод заметил: `canvas_hash` совпадает у 34 из 40 аккаунтов. `fonts_hash` — у 38. Разрешение экрана `1366x768` — у всех. И `tz_offset` показывает `-120`, хотя для `Europe/Amsterdam` в июне должно быть `-120` (CEST), а в декабре `-60` (CET). Аккаунты заходили в разные месяцы, но offset не менялся — значит, таймзона захардкожена в конфиге браузера, а не берётся из системы.

Результат: все 40 аккаунтов заблокированы в течение суток. Прокси-пул сожжён.

Кейс: несовпадение языка и валюты

Другой маркетплейс, категория "одежда". Аккаунт зарегистрирован на российский номер, платит картой РФ, но `navigator.language` = `en-US`, таймзона `America/New_York`, IP из Нью-Джерси. Вроде логично — человек в США.

Но `Intl.NumberFormat().resolvedOptions().currency` вернул `RUB`. Это значит, что в системе браузера валюта по умолчанию — рубль, хотя локаль американская. Антифрод пометил: локаль подменена, системные настройки остались российскими. Аккаунт ушёл на ручную проверку, потом в бан.

Причина: пользователь выставил язык и таймзону через расширение, но не тронул региональные настройки ОС. Антифрод читает их через `Intl` API и видит несоответствие.

Как выглядит корректная маскировка

Если нужно легитимно работать с нескольких аккаунтов (например, для тестирования), консистентность обязательна. Таймзона, язык, формат даты, валюта, IP — всё должно указывать на один регион.

Проверка через curl:

```bash

curl -s https://api.ipapi.com/159.89.44.12?access_key=KEY | jq '{country_code, timezone, currency}'

```

Ответ:

```json

{

"country_code": "US",

"timezone": "America/New_York",

"currency": "USD"

}

```

Дальше браузер должен показывать ровно эти значения. Не `Europe/Moscow`, не `RUB`. Если используешь антидетект-браузер, проверяй через такой скрипт:

```python

from playwright.sync_api import sync_playwright

with sync_playwright() as p:

browser = p.chromium.launch()

page = browser.new_page()

page.goto("about:blank")

result = page.evaluate("""() => ({

tz: Intl.DateTimeFormat().resolvedOptions().timeZone,

lang: navigator.language,

currency: Intl.NumberFormat().resolvedOptions().currency,

date: new Intl.DateTimeFormat().format(new Date()),

offset: new Date().getTimezoneOffset()

})""")

print(result)

browser.close()

```

Вывод должен совпадать с гео IP. Если `tz` = `America/New_York`, а `offset` = `-180` (МСК) — косяк. Для Нью-Йорка летом offset `-240`, зимой `-300`.

Что делать с прокси

Прокси — это первое, что проверяет антифрод. Дата-центровые IP палятся мгновенно: ASN принадлежит хостингу, а не residential-провайдеру. MaxMind отдаёт флаг `is_hosting: true`. Вес к подозрительности растёт сразу.

Для IPv6 ситуация сложнее. Residential IPv6-прокси реже, но их сложнее отследить, потому что пулы огромные. Один `/64` префикс может содержать миллиарды адресов. Антифрод не может заблокировать весь префикс — там живут реальные пользователи. Поэтому IPv6-прокси с правильной геолокацией и консистентной таймзоной проходят чаще, чем IPv4 из дата-центра.

Сервисы вроде lexic.ml дают IPv6-адреса с привязкой к региону. Если брать адрес в Германии — таймзона должна быть `Europe/Berlin`, язык `de-DE`, валюта `EUR`. Тогда связка IP↔TZ↔lang не вызывает вопросов. Но если тот же адрес использовать с `ru-RU` и `Europe/Moscow` — антифрод свяжет аккаунты по несоответствию быстрее, чем по IP.

Итоговая логика антифрода

Система не ищет "плохих". Она строит граф и ищет аномалии. Таймзона и язык — два узла, которые почти всегда коррелируют с IP. Если корреляция нарушена — сигнал. Если нарушение повторяется на разных аккаунтах — кластер. Если кластер совпадает с другими сигналами (canvas, fonts, поведение) — бан.

Обойти это можно только полной консистентностью. Не подменой одного поля, а согласованностью всех: IP, ASN, гео, таймзона, язык, локаль, валюта, формат даты, поведение. Как только одно звено выпадает — антифрод это видит. И запоминает.

✔️Купить прокси