Что сайт видит о посетителе при работе через прокси
Сайт видит адрес того соединения, которое до него дошло: при работе через прокси это адрес посредника из пула, адрес рабочей машины до площадки не добирается. Всё остальное площадка собирает у браузера напрямую: строку User-Agent, набор и порядок заголовков запроса, отпечаток TLS-рукопожатия, язык интерфейса, часовой пояс, разрешение экрана, список шрифтов, cookies и ритм действий за страницей.
Отсюда рабочее правило, вокруг которого построена вся статья: посредник закрывает сетевой слой, признаки прикладного слоя остаются на стороне браузера и настраиваются отдельно. Ниже разобран каждый признак по порядку: кто его отдаёт, что по нему определяется на стороне площадки и чем он закрывается. В конце собрана сводная таблица по всем признакам сразу.
Адрес соединения: что читается по одной строке в логе
Первое, что попадает в журнал веб-сервера, это адрес источника TCP-соединения. Через посредника туда пишется адрес выходного узла. Мы держим пул около 12 000 активных адресов, ротация внутри него автоматическая, поэтому два соседних запроса штатно уходят с разных выходов и в логе площадки выглядят как обращения разных клиентов.
Сам адрес это только начало. За секунду по нему поднимается целый пласт сведений, и делает это любой желающий парой запросов из командной строки.
whois 203.0.113.24 | grep -iE "netname|descr|origin|country"
dig +short 24.113.0.203.origin.asn.cymru.com TXT
Первая команда отдаёт владельца диапазона, границы блока и контакты. Вторая показывает номер автономной системы, внутри которой этот блок анонсируется. Крупные площадки хранят собственные списки автономных систем и раскладывают входящий трафик по ним ещё до того, как отработает страница. Соседи по подсети тоже учитываются: когда из блока /24 идёт однородный поток запросов, счётчики срабатывают на весь диапазон.
| Что берётся из адреса | Источник сведений | Насколько точно |
|---|---|---|
| Владелец диапазона | База регионального регистратора, whois | Точно, запись публичная |
| Номер автономной системы | Таблица маршрутов, публичные сервисы | Точно |
| Тип сети | Классификация автономной системы | Достоверно на уровне категории |
| Приблизительная география | Коммерческие базы геолокации | С расхождениями, базы отстают |
| Соседи по подсети | Границы блока из whois | Точно |
| История обращений | Внутренние счётчики самой площадки | Зависит от площадки |
Про принадлежность блоков и поведение соседей по диапазону у нас есть отдельный разбор в материале про подсеть и диапазон. Здесь важен один вывод: адрес отдаёт сеть, и через посредника площадка читает сеть посредника. Наши выходные узлы стоят на собственном оборудовании, как устроены такие серверные адреса на своём железе, расписано на отдельной странице.
Строка User-Agent и заголовки Client Hints
User-Agent это текстовая строка, которую браузер добавляет к каждому запросу. Она сообщает семейство браузера, версию движка, платформу и разрядность системы. Посредник её не трогает и не переписывает: строка формируется программой на стороне пользователя.
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36
Современные браузеры на движке Chromium дополняют картину заголовками Client Hints. Часть из них уходит с каждым запросом сама, часть подтягивается по запросу площадки через заголовок Accept-CH. Смысл тот же, форма аккуратнее: значения разложены по отдельным полям и читаются машиной без разбора длинной строки.
Sec-CH-UA: "Chromium";v="126", "Google Chrome";v="126", "Not.A/Brand";v="24"
Sec-CH-UA-Platform: "Windows"
Sec-CH-UA-Platform-Version: "15.0.0"
Sec-CH-UA-Arch: "x86"
Sec-CH-UA-Bitness: "64"
Sec-CH-UA-Full-Version-List: "Chromium";v="126.0.6478.127"
Здесь появляется первый источник расхождений. Пользователь подменил User-Agent расширением, площадка запросила Client Hints, и в ответ пришла платформа, которая с подменённой строкой не сходится. Мы видим этот сценарий регулярно в обращениях: адрес из пула отрабатывает штатно, площадка отдаёт проверку, а причина сидит в двух полях, которые рассказывают о системе разные вещи. Подмена работает только тогда, когда её делает сам браузер на уровне движка, и ровно для этого существуют антидетект-браузеры с подменой отпечатка.
Набор и порядок заголовков запроса
Заголовки различаются двумя вещами: составом и последовательностью. Состав отвечает на вопрос, какие поля вообще есть в запросе. Последовательность это порядок их следования, и он у каждой программы свой, устойчивый от запуска к запуску.
Браузер на Chromium отправляет поля примерно в таком порядке.
:method: GET
:authority: example.com
:scheme: https
:path: /catalog
sec-ch-ua: ...
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 ...
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif
sec-fetch-site: none
sec-fetch-mode: navigate
sec-fetch-user: ?1
sec-fetch-dest: document
accept-encoding: gzip, deflate, br, zstd
accept-language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
Скрипт на requests отправляет четыре поля в другом порядке и без единого заголовка группы Sec-Fetch. Библиотека честно сообщает о себе строкой python-requests/2.31, и площадке этого достаточно для однозначной классификации. Подстановка браузерного User-Agent поверх такого запроса картину не выравнивает: порядок полей и отсутствие группы Sec-Fetch остаются на месте.
| Поле | Что сообщает площадке | Кто его формирует |
|---|---|---|
Accept | Какие типы содержимого принимает клиент | Программа |
Accept-Language | Языки интерфейса и их приоритет | Настройки браузера |
Accept-Encoding | Поддерживаемые способы сжатия | Программа |
Sec-Fetch-Site | Откуда инициирован переход | Браузер, скриптом не подделывается |
Sec-Fetch-Dest | Что запрашивается: документ, картинка, шрифт | Браузер |
Referer | Предыдущая страница в цепочке | Браузер либо код запроса |
Via, X-Forwarded-For | Факт прохождения через посредника | Посредник |
Последняя строка таблицы касается уже самого посредника. Обычный прозрачный шлюз дописывает к запросу служебные поля с адресом исходного клиента, и тогда вся конструкция теряет смысл: площадка читает исходный адрес прямо из заголовка. Мы такие поля к запросу не добавляем: выход отдаёт площадке только свой адрес. Про ступени подмены подробно написано в разборе анонимных прокси без служебных заголовков, там же собран список заголовков для первой проверки.
Проверяется состав заголовков одной командой к эхо-сервису. Ответ приходит списком полей ровно в том виде, в каком их получил удалённый сервер, поэтому лишнее поле видно сразу и без разбора трафика.
curl -s -x http://203.0.113.24:8000 https://httpbin.org/headers | jq .headers
Отдельного внимания требует группа Sec-Fetch. Браузер заполняет её сам на уровне движка, скриптом эти поля не переопределяются, и по ним площадка отличает переход по ссылке от прямого обращения к адресу страницы. Запрос от библиотеки приходит без всей группы целиком, и это самый дешёвый способ классификации из всех, которые площадка может себе позволить.
Отпечаток TLS: рукопожатие до первого байта HTTP
Прежде чем уйдёт первый заголовок HTTP, клиент и сервер обмениваются пакетами TLS. Первый пакет клиента, ClientHello, содержит версию протокола, список поддерживаемых шифров, набор расширений, эллиптические кривые, алгоритмы подписи и список протоколов ALPN. Всё это идёт в определённом порядке, и порядок задаётся библиотекой шифрования, которую использует программа.
Из этого набора считается короткая подпись. Схема JA3 сворачивает поля ClientHello в хеш, более свежая JA4 разбивает подпись на читаемые части и устойчивее к перестановке расширений. Площадке достаточно посчитать подпись на границе сети и сравнить со списком известных значений.
# сравнение отпечатков двух клиентов через публичный сервис
curl --socks5-hostname 203.0.113.24:1080 https://tls.peet.ws/api/all | jq .tls.ja3_hash
Расхождение выглядит так. В заголовке заявлен Chrome под Windows, а рукопожатие приходит от OpenSSL со списком шифров, которого у Chrome никогда не было. Площадка сопоставляет два признака за один шаг. Мы разбирали такие обращения десятки раз: адреса пула отвечают ровно, отклик стабильный, отказ приходит из-за библиотеки, которая ходит своим рукопожатием.
Отпечаток TLS формируется клиентской программой целиком. Посредник переносит байты рукопожатия дальше без изменений, потому что содержимое туннеля ему недоступно. Выравнивается признак заменой транспорта: браузер вместо библиотеки либо библиотека с имитацией браузерного ClientHello, такие сборки существуют для Go, Python и Node.
Что отдаёт сам браузер: язык, пояс, экран и шрифты
Следующая группа признаков рождается внутри браузера и до сети вообще не относится. Скрипт на странице читает их обычными вызовами, без разрешений и без диалоговых окон. Посредник тут ничего изменить не может: он переносит уже готовые байты.
Язык, часовой пояс и локаль
Язык уходит двумя путями сразу. Первый это заголовок Accept-Language, он приходит с каждым запросом. Второй это свойства объекта navigator, которые читает любой скрипт на странице. Часовой пояс скрипт получает через штатный интерфейс интернационализации.
navigator.language // "ru-RU"
navigator.languages // ["ru-RU", "ru", "en-US", "en"]
Intl.DateTimeFormat().resolvedOptions().timeZone // "Europe/Moscow"
new Date().getTimezoneOffset() // -180
Дальше площадка сравнивает три величины: приблизительную географию адреса, часовой пояс браузера и языковой список. Совпадение всех трёх выглядит естественно. Расхождение между поясом и адресом само по себе встречается у миллионов обычных пользователей в поездках, поэтому один такой признак ничего не решает, вес он набирает в сочетании с остальными.
Наш пул это микс со всего мира, адреса приходят из множества стран, выборка по отдельной стране не делается. Практический вывод простой: языковой список и пояс настраиваются в профиле браузера один раз под ту картину, которая нужна для работы, и дальше остаются постоянными от сессии к сессии. Постоянство здесь весит больше, чем конкретное значение.
Экран, графика и набор шрифтов
Скрипт на странице читает геометрию окна и параметры экрана без всяких разрешений. Доступны ширина и высота, рабочая область без панелей, глубина цвета, плотность пикселей.
screen.width + "x" + screen.height // 1920x1080
screen.availHeight // 1032
window.devicePixelRatio // 1.25
Отдельная группа признаков идёт от подсистемы графики. Отрисовка текста и фигур в элемент canvas даёт слегка разный результат на разных связках драйвера, шрифтового движка и видеокарты, и хеш от полученной картинки работает как метка. Через WebGL читается строка производителя и модели видеоадаптера. Через звуковой контекст снимается похожая подпись на уровне обработки сигнала.
Шрифты перебираются проверкой ширины тестовой строки: скрипт рисует одну и ту же надпись сотней шрифтов и смотрит, где ширина изменилась. Набор установленных шрифтов сильно различается между машинами, поэтому список даёт заметный вклад в общий отпечаток.
| Признак | Как снимается | Что различает |
|---|---|---|
| Разрешение экрана | Свойства объекта screen | Модель монитора и настройки системы |
| Плотность пикселей | devicePixelRatio | Масштабирование интерфейса |
| Canvas | Хеш отрисованной картинки | Связку драйвера и шрифтового движка |
| WebGL | Строка производителя и модели адаптера | Видеокарту |
| AudioContext | Подпись обработанного сигнала | Звуковой стек системы |
| Шрифты | Перебор по ширине тестовой строки | Состав установленных шрифтов |
| WebRTC | Служебный обмен кандидатами соединения | Внутренние адреса сетевых интерфейсов |
Последняя строка требует внимания отдельно: механизм голосовой связи в браузере умеет сообщать адреса сетевых интерфейсов мимо посредника. Проверяется и отключается он в пару шагов, порядок описан в материале про проверку и отключение WebRTC.
Cookies, хранилище и кеш
Cookies это самая старая и самая надёжная метка, которую площадка ставит сама. Она пережила все поколения приватных режимов просто потому, что её выдаёт сервер и хранит браузер. Посредник к содержимому хранилища отношения не имеет: файлы лежат в профиле на диске рабочей машины.
Кроме cookies браузер держит localStorage, sessionStorage, базы IndexedDB, кеш сервис-воркеров и кеш HTTP. Последний тоже работает меткой: сервер отдаёт картинку с уникальным значением ETag, браузер при следующем визите присылает это значение обратно в заголовке If-None-Match, и площадка узнаёт посетителя без единой cookie.
Отсюда самое частое расхождение ожиданий. Человек берёт адрес из пула, открывает ту же вкладку того же браузера и обнаруживает прежнюю сессию. Причина лежит в профиле: адрес сменился, хранилище осталось прежним. Мы советуем разводить задачи по отдельным профилям браузера, чтобы каждому набору задач соответствовало своё хранилище и свой набор меток.
Поведение: мышь, клавиатура и ритм запросов
Последняя группа признаков снимается уже во время работы со страницей. Скрипты собирают траекторию курсора, паузы между нажатиями клавиш, скорость прокрутки, время до первого клика, порядок обхода полей формы. Живая работа даёт неровные интервалы: человек задумывается, возвращается, промахивается мимо кнопки.
Автоматический обход выглядит иначе. Курсор перемещается по прямой либо не перемещается вовсе, текст в поле появляется целиком за один тик, интервал между запросами держится ровным до миллисекунды. Ровный интервал вообще самый заметный из поведенческих признаков, потому что для его подсчёта скрипты не нужны: достаточно журнала обращений на стороне сервера.
| Поведенческий признак | Что выдаёт автоматику | Как выравнивается |
|---|---|---|
| Траектория курсора | Прямая линия либо полное отсутствие движения | Эмуляция движений в софте |
| Скорость ввода | Мгновенная вставка целой строки | Посимвольный ввод с разбросом пауз |
| Интервал между запросами | Одинаковые промежутки в журнале сервера | Случайная задержка в заданных границах |
| Глубина просмотра | Один запрос на страницу, ноль прокрутки | Догрузка сопутствующих файлов |
| Параллельность | Десятки одновременных обращений с одного выхода | Распределение по адресам пула |
Последний пункт напрямую связан с числом доступных выходов. Стандартные пакеты дают до 1000 потоков, корпоративный до 3000, при двух привязанных адресах общий лимит делится пополам. Ротация внутри пула автоматическая, поэтому параллельная нагрузка расходится по разным адресам сама, без ручного распределения на стороне софта. Как это устроено со стороны пакета, описано на странице, где можно купить прокси IPv4 с доступом к пулу.
Сводная таблица: признак, кто его отдаёт, чем закрывается
Ниже собрано всё разобранное выше в одном месте. Колонка «кто отдаёт» отвечает на вопрос, где физически рождается признак. Колонка «чем закрывается» показывает, какой инструмент за него отвечает.
| Признак | Кто его отдаёт | Чем закрывается |
|---|---|---|
| Адрес соединения | Сетевой стек, узел на маршруте | Прокси, адрес берётся из пула |
| Владелец диапазона и номер AS | Публичные базы по адресу выхода | Прокси, характеристика выходного узла |
| Служебные заголовки посредника | Сам посредник | Прокси без подстановки служебных полей |
| Запрос к службе имён | Сетевые настройки программы | SOCKS5 с разрешением имён на стороне выхода |
| WebRTC | Браузер, обмен кандидатами соединения | Настройка браузера, отключение механизма |
| User-Agent | Браузер либо программа | Профиль антидетект-браузера |
| Client Hints | Браузер на движке Chromium | Профиль антидетект-браузера |
| Состав и порядок заголовков | Программа, которая шлёт запрос | Выбор клиента, браузерная сборка библиотеки |
| Отпечаток TLS | Библиотека шифрования клиента | Браузер либо сборка с браузерным ClientHello |
| Язык и часовой пояс | Настройки браузера и системы | Профиль браузера, постоянные значения |
| Экран и плотность пикселей | Браузер, свойства объекта screen | Профиль браузера |
| Canvas, WebGL, AudioContext | Графический и звуковой стек машины | Профиль антидетект-браузера с подменой |
| Набор шрифтов | Система | Профиль антидетект-браузера |
| Cookies и хранилище | Браузер, файлы профиля на диске | Отдельный профиль под каждую задачу |
| Поведение и ритм запросов | Действия пользователя либо софта | Настройки пауз и параллельности в софте |
Читается таблица сверху вниз как порядок работ. Первые четыре строки закрывает пакет прокси. Строка про WebRTC требует одной галочки в настройках браузера. Всё, что ниже, живёт в профиле браузера и в настройках рабочей программы.
Полезно смотреть на вес строк. Адрес соединения и служебные заголовки посредника весят больше всего, потому что они попадают в журнал сервера при каждом обращении и разбираются без единой строки скрипта. Отпечаток TLS идёт следом: подпись считается на границе сети, до разбора запроса. Графические подписи и набор шрифтов набирают вес медленнее и работают в связке с остальными признаками. Поведенческая группа замыкает список, зато именно она чаще всего срабатывает на длинных прогонах, когда транспорт и профиль давно настроены и повторяется один и тот же ритм обращений.
Ещё один вывод касается порядка исправлений. Признаки сетевого слоя закрываются один раз выбором пакета и настройкой доступа. Это самая быстрая часть работы: наши пакеты с высокой ступенью подмены дают выход без служебных полей, и дальше к нему уже не возвращаются. Признаки браузера требуют настройки профиля, а поведение настраивается в самом софте, и обе эти части живут своей жизнью от задачи к задаче.
Как собрать признаки в согласованный набор
Сначала фиксируется транспорт. Для браузерных задач берём HTTP и HTTPS, для программ с произвольными портами и скриптов удобнее прокси SOCKS5 для программ и скриптов: имя домена разрешается на стороне выходного узла, и запросы к службе имён не уходят мимо туннеля. Про эту утечку и её проверку есть отдельный разбор в материале про запросы к DNS. В пакете доступны IPv4, HTTP, HTTPS, SOCKS4 и SOCKS5, адреса при этом одни и те же, меняется только строка подключения, поэтому переход с одного протокола на другой ничего не стоит по времени.
Дальше собирается профиль браузера. Один профиль это одна задача: своя строка User-Agent, свой язык, свой часовой пояс, своё хранилище, свой набор графических подписей. Профиль запоминается целиком и переиспользуется, потому что постоянство признаков от сессии к сессии выглядит естественнее, чем свежий набор при каждом запуске.
Третий шаг это проверка. Сверяем адрес на выходе, состав заголовков, отпечаток TLS и утечку через WebRTC. Проверка занимает несколько минут и снимает большую часть будущих вопросов, а подробный порядок с командами разобран на странице про проверку анонимности.
# что видит площадка: адрес, заголовки и отпечаток рукопожатия
curl -x http://203.0.113.24:8000 https://ifconfig.me
curl -x http://203.0.113.24:8000 https://httpbin.org/headers
curl -x http://203.0.113.24:8000 https://tls.peet.ws/api/all
Четвёртый шаг это нагрузка. Интервалы между запросами задаются с разбросом, параллельность держится в пределах лимита пакета, тяжёлые прогоны разносятся по времени. Пул около 12 000 адресов и автоматическая ротация дают разнообразие выходов, дальше картину формирует сам софт своими настройками. Совокупность из ровного транспорта, постоянного профиля и разумного ритма работает заметно лучше, чем любой из трёх пунктов по отдельности, и именно в таком составе мы рекомендуем её собирать.
Частые вопросы
Закрывает ли прокси отпечаток браузера?
Прокси закрывает сетевой слой: площадка принимает соединение от выходного узла и записывает в журнал его адрес. Строка User-Agent, заголовки Client Hints, отпечаток TLS, шрифты, экран и графические подписи рождаются на стороне клиентской программы, поэтому за них отвечают настройки браузера и профиль антидетекта. Оба слоя нужны вместе, и таблица выше показывает, какой инструмент закрывает какую строку. Сетевую часть целиком берут на себя прокси с высокой ступенью анонимности, которые отдают площадке только адрес выходного узла.
Как проверить, какой адрес видит площадка?
Один запрос через curl на сервис, который возвращает адрес обращения, показывает выходной узел за секунду. Для массовой проверки списка подойдёт чекер от Zennolab, у него есть демонстрационная версия: он проходит список пачкой и показывает отвечающие строки, время отклика и тип прокси. Перед покупкой доступен бесплатный тест до 2 часов, и проверку удобно провести именно в нём, на своём софте и своих целевых доменах.
Почему адрес в двух запросах подряд разный?
Ротация внутри пула автоматическая, список из примерно 12 000 адресов обновляется в режиме реального времени. Соседние запросы штатно уходят с разных выходов, и это признак исправной работы пула. Если задача требует держать серию обращений с одного выхода, порядок настраивается на стороне софта через параметры сессии и длину пачки запросов.
Можно ли получить адреса определённой страны?
Нет, наш пул это микс со всего мира, выборка по отдельной стране не делается. Адреса приходят из множества стран, всего в списке представлено 200+ стран, и такая схема даёт разнообразие подсетей без ручной настройки. Для сбора открытых данных, проверки выдачи и работы с несколькими кабинетами разнообразие подсетей весит больше, чем конкретная точка на карте.
Продолжение темы в соседних материалах раздела: уровни анонимности прокси с разбором служебных заголовков по ступеням, что такое прокси IPv4 с полным путём запроса по шагам, серверные адреса и их происхождение. Практическую часть закрывает статья про проверку работы прокси с командами и разбором кодов ответа.