HTTP-прокси и SOCKS5 на уровне протокола: CONNECT, ATYP, что видит посредник и как выбирать
Содержание статьи
- Введение: почему один прокси выдаётся в двух режимах и это не маркетинг
- Основы: где прокси живёт в сетевом стеке
- Http-прокси: запрос с абсолютным uri, что прокси видит и может изменить
- Метод connect: превращение http-прокси в tcp-туннель
- Socks5: рукопожатие, аутентификация и atyp
- Сравнение по критериям: где каждый выигрывает
- Что выбрать под задачу: таблица
- Совместимость в популярных клиентах и библиотеках
- Кейсы из инженерной практики
- Частые заблуждения
- Faq
- Заключение
Если вы хоть раз открывали личный кабинет прокси-сервиса, вы видели эту картину: один и тот же адрес, один и тот же логин, а рядом два порта. Один подписан HTTP, второй SOCKS5. Многие выбирают наугад или по привычке. Между тем за этими двумя строчками стоят два разных протокола, которые по-разному устроены на уровне байтов, по-разному видят ваш трафик и по-разному ведут себя в реальных клиентах. Это руководство разбирает разницу до последнего байта и заканчивается практическими таблицами выбора.
Введение: почему один прокси выдаётся в двух режимах и это не маркетинг
Начнём с честного ответа на вопрос из заголовка. Когда Proxeon выдаёт вам адрес с двумя портами, за ними стоит одна и та же машина, один и тот же исходящий IP-адрес и одна и та же учётная запись. Разница не в том, куда уходит трафик. Разница в том, на каком языке ваш клиент разговаривает с прокси-сервером на первом участке пути: от вашего приложения до посредника.
HTTP-прокси разговаривает на языке HTTP. Он принимает HTTP-запросы, читает их, понимает, что вы хотите получить, и сам ходит за ресурсом. Он умеет кэшировать, добавлять заголовки, отвечать кодами состояния. Для всего, что не является HTTP, у него есть один универсальный приём: метод CONNECT, который превращает его в тупую трубу.
SOCKS5 вообще не знает, что такое HTTP. Это протокол уровня сессии: клиент говорит «соедини меня вот с таким хостом и портом», прокси открывает TCP-соединение и с этого момента просто перекладывает байты туда и обратно. Ему безразлично, что внутри: TLS, IMAP, SSH, протокол базы данных или ваш собственный бинарный формат.
Почему нельзя оставить только один режим? Потому что у них разная совместимость. Половина корпоративного и десктопного софта умеет только HTTP-прокси через системные настройки. Значительная часть сетевых библиотек и практически весь не-веб трафик комфортнее чувствует себя в SOCKS5. Отдавать оба режима на одном IP означает, что вы выбираете инструмент под клиента, а не подгоняете клиента под инструмент.
Что вы узнаете из этой статьи:
- как выглядит запрос к HTTP-прокси на уровне текста и чем он отличается от обычного запроса к сайту;
- что именно прокси видит и может изменить в прозрачном HTTP-режиме;
- как работает метод CONNECT и что остаётся видно посреднику после установления туннеля;
- байтовое рукопожатие SOCKS5, схемы аутентификации и три типа адресов ATYP;
- почему выбор между доменом и IP в SOCKS5-запросе влияет на геолокацию и приватность DNS;
- сравнение по не-HTTP протоколам, UDP, накладным расходам, кэшированию и логированию;
- таблицу «задача, протокол, почему» и разбор совместимости в популярных клиентах и библиотеках.
Механику команды UDP ASSOCIATE и разницу между схемами socks5 и socks5h в curl и Python мы здесь подробно не разбираем: этим темам посвящены отдельные материалы в блоге Proxeon, на них будут ссылки в нужных местах.
Основы: где прокси живёт в сетевом стеке
Чтобы разговор о протоколах имел смысл, договоримся о терминах. Их немного.
Три участника и два соединения
В любой схеме с прокси есть три стороны: клиент (ваш браузер, скрипт, почтовая программа), прокси-сервер (посредник) и целевой сервер (origin). Между ними два независимых TCP-соединения. Первое: клиент к прокси. Второе: прокси к целевому серверу. Целевой сервер видит только второе соединение и, соответственно, только IP-адрес прокси.
Всё, что мы обсуждаем в этой статье, касается исключительно первого соединения. Именно там живёт разница между HTTP и SOCKS5. Второе соединение в обоих случаях устроено одинаково: обычный TCP от прокси до целевого хоста.
Уровни модели и почему это важно
Полезная аналогия: представьте курьерскую службу. HTTP-прокси в прозрачном режиме похож на курьера, который открывает вашу посылку, читает адрес и содержимое, при необходимости переупаковывает и может даже ответить сам, если у него на складе лежит копия. SOCKS5 похож на курьера, которому вы называете адрес, а посылку отдаёте запечатанной. Он не знает и не хочет знать, что внутри.
Если говорить в терминах сетевой модели, HTTP-прокси работает на прикладном уровне: он понимает семантику запроса. SOCKS5 работает на сеансовом уровне: он оперирует понятиями «хост», «порт», «соединение» и не поднимается выше.
Где происходит разрешение имён
Отдельный концепт, который проходит красной нитью через весь материал: DNS-резолв. Когда вы обращаетесь к example.com, кто-то должен превратить имя в IP-адрес. Это может сделать ваш клиент локально, а может прокси на своей стороне. От этого зависит, чью DNS-инфраструктуру вы используете, какой региональный ответ получите от CDN и утекает ли информация о посещаемых доменах в локальную сеть. Запомните этот пункт, он всплывёт и в разделе про HTTP, и в разделе про SOCKS5.
Аутентификация
И HTTP-прокси, и SOCKS5 умеют проверять логин и пароль, но делают это по-разному. HTTP использует заголовок Proxy-Authorization и код ответа 407. SOCKS5 использует отдельный подпротокол с номером метода 0x02. Есть и альтернатива, не зависящая от протокола: авторизация по IP-адресу клиента, когда прокси пускает всех, кто пришёл с заранее разрешённого адреса. В Proxeon доступны оба варианта, и выбор между ними влияет на то, насколько просто подключить клиенты, которые не умеют передавать учётные данные.
HTTP-прокси: запрос с абсолютным URI, что прокси видит и может изменить
Обычный HTTP-запрос к сайту выглядит так:
GET /catalog/items?page=2 HTTP/1.1
Host: shop.exampleОбратите внимание: в строке запроса стоит только путь. Хост передаётся отдельным заголовком. Такой формат называется origin-form. Когда клиент знает, что общается не с сайтом, а с прокси, он меняет формат на absolute-form: в строку запроса помещается полный URI.
GET http://shop.example/catalog/items?page=2 HTTP/1.1
Host: shop.example
Proxy-Authorization: Basic dXNlcjpwYXNz
User-Agent: my-parser/1.0
Accept: text/htmlЗачем дублировать хост? Исторически абсолютная форма появилась раньше заголовка Host и была единственным способом сказать прокси, куда идти. Современный стандарт HTTP/1.1 требует от прокси уметь принимать абсолютную форму, а от клиентов, обращающихся к прокси, использовать именно её. Заголовок Host при этом сохраняется для совместимости и для целевого сервера, которому прокси перешлёт запрос уже в origin-form.
Что HTTP-прокси видит
В прозрачном режиме (без шифрования между клиентом и целевым сайтом) прокси видит абсолютно всё, что есть в запросе и ответе:
- метод, полный URL, включая query-параметры;
- все заголовки запроса: User-Agent, Cookie, Authorization, Referer;
- тело запроса целиком: формы, JSON, загружаемые файлы;
- статус ответа, заголовки ответа и тело ответа.
Это не побочный эффект. Это фундаментальная особенность архитектуры: чтобы переслать запрос, прокси обязан его распарсить. А раз он его распарсил, он может делать с ним всё что угодно.
Что HTTP-прокси может изменить
Стандарт делит заголовки на сквозные (end-to-end) и пошаговые (hop-by-hop). Пошаговые заголовки относятся к одному конкретному соединению и обязаны удаляться прокси перед пересылкой. К ним относятся Connection, Keep-Alive, Proxy-Authorization, Proxy-Authenticate, TE, Trailer, Transfer-Encoding, Upgrade. Именно поэтому ваш логин и пароль от прокси не улетают на целевой сайт: заголовок Proxy-Authorization по стандарту снимается на прокси.
Кроме обязательной чистки прокси может:
- добавить заголовок Via с указанием своего имени и версии протокола; стандарт этого требует, но на практике анонимные прокси его опускают;
- добавить X-Forwarded-For с реальным IP клиента; так делают корпоративные прокси, и так никогда не должен делать прокси, который вы покупаете для работы с внешними ресурсами;
- отдать ответ из своего кэша, не обращаясь к целевому серверу, если ответ помечен как кэшируемый;
- изменить кодировку тела, добавить или снять сжатие, переписать ссылки в HTML;
- отклонить запрос своим собственным ответом, например 403 или 407.
Ответ 407 Proxy Authentication Required заслуживает отдельного упоминания. Если прокси требует авторизацию, а клиент её не прислал, прокси отвечает именем 407 и заголовком Proxy-Authenticate, где перечисляет поддерживаемые схемы. Хорошие клиенты после этого повторяют запрос с Proxy-Authorization. Плохие клиенты показывают пользователю непонятную ошибку. Отсюда типичная проблема при настройке: приложение «не видит прокси», хотя на деле оно просто не умеет обрабатывать 407.
Разбираем на практике
Самый простой способ увидеть всё это своими глазами: curl с ключом -v.
curl -v -x http://user:pass@gate.proxeon.net:8080 http://httpbin.org/getВ выводе вы увидите строку вида GET http://httpbin.org/get HTTP/1.1 и заголовок Proxy-Authorization. Это и есть абсолютная форма.
Тот же запрос руками через сокет на Python, чтобы не осталось магии:
import socket, base64
creds = base64.b64encode(b"user:pass").decode()
req = (
"GET http://httpbin.org/get HTTP/1.1\r\n"
"Host: httpbin.org\r\n"
f"Proxy-Authorization: Basic {creds}\r\n"
"Connection: close\r\n\r\n"
)
s = socket.create_connection(("gate.proxeon.net", 8080))
s.sendall(req.encode())
print(s.recv(65535).decode(errors="replace"))Здесь нет ни одной библиотеки для прокси. Только сокет и правильно составленная строка. HTTP-прокси в прозрачном режиме настолько прост, что его можно написать за вечер, и в этом одновременно его сила и слабость.
Где резолвится имя в HTTP-режиме
В абсолютной форме клиент передаёт прокси имя хоста как есть. Резолв выполняет прокси. Клиенту не нужно знать IP-адрес целевого сервера, и локальный DNS-запрос не выполняется. Это удобно, но приводит нас к главному ограничению: описанная схема работает только для незашифрованного HTTP. Для HTTPS абсолютная форма бесполезна, потому что TLS-соединение должно быть установлено между клиентом и целевым сервером, а прокси не может встать посередине, не сломав сертификат. Для этого и придуман CONNECT.
Метод CONNECT: превращение HTTP-прокси в TCP-туннель
CONNECT это метод HTTP, который просит прокси не пересылать запрос, а установить TCP-соединение с указанным хостом и портом, после чего стать прозрачной трубой. Запрос выглядит так:
CONNECT shop.example:443 HTTP/1.1
Host: shop.example:443
Proxy-Authorization: Basic dXNlcjpwYXNz
Proxy-Connection: Keep-AliveОбратите внимание на формат цели: только хост и порт, без схемы и пути. Это authority-form запроса, третий из форматов после origin-form и absolute-form.
Если прокси согласен, он отвечает:
HTTP/1.1 200 Connection establishedТекст после кода может быть любым, клиенты ориентируются только на 2xx. С этого момента HTTP заканчивается. Всё, что клиент пишет в сокет, прокси байт в байт пересылает целевому серверу, и наоборот. Клиент начинает TLS-рукопожатие прямо в этом сокете, как если бы был подключён к серверу напрямую.
Что посредник видит после CONNECT
Здесь начинается самое интересное. Прокси, который только что был всевидящим, резко слепнет. После успешного CONNECT прокси знает:
- имя хоста и порт из строки CONNECT; это единственная семантическая информация, которую он получил;
- время установления и закрытия соединения;
- объём переданных байтов в обе стороны;
- содержимое TLS ClientHello, если внутри туннеля TLS: там в открытом виде передаётся SNI (имя сервера), список поддерживаемых шифров, расширения; современное расширение Encrypted Client Hello скрывает и SNI, но его поддержка пока не повсеместна;
- ничего из HTTP-уровня: ни URL, ни заголовков, ни куки, ни тела.
Иными словами, после CONNECT HTTP-прокси видит ровно столько же, сколько SOCKS5. Хост, порт, тайминги, объёмы. Разница в видимости между двумя протоколами существует только для незашифрованного HTTP-трафика, а его в 2026 году в реальных задачах осталось очень мало.
CONNECT не обязан вести к HTTPS
Распространённая ошибка мышления: CONNECT нужен только для HTTPS. На самом деле стандарт не ограничивает содержимое туннеля. Через CONNECT можно установить соединение с IMAP-сервером на порт 993, с SSH на порт 22, с любым TCP-сервисом. Вопрос только в том, разрешает ли это конфигурация прокси. Многие публичные и корпоративные HTTP-прокси разрешают CONNECT только на порты 443 и иногда 80, чтобы предотвратить злоупотребления. Proxeon разрешает CONNECT на произвольные порты, но если ваш софт умеет SOCKS5, для не-HTTP протоколов он остаётся более естественным выбором, о чём ниже.
Пример: TLS через CONNECT руками
Утилита openssl умеет пройти через HTTP-прокси самостоятельно:
openssl s_client -proxy gate.proxeon.net:8080 -connect shop.example:443 -servername shop.exampleА вот как это выглядит на Python со стандартной библиотекой, без внешних зависимостей:
import http.client, ssl
conn = http.client.HTTPSConnection("gate.proxeon.net", 8080,
context=ssl.create_default_context())
conn.set_tunnel("shop.example", 443,
headers={"Proxy-Authorization": "Basic dXNlcjpwYXNz"})
conn.request("GET", "/")
resp = conn.getresponse()
print(resp.status, resp.getheader("server"))Метод set_tunnel делает ровно то, что описано выше: отправляет CONNECT, ждёт 200, затем оборачивает сокет в TLS. Заметьте, что TLS-контекст проверяет сертификат именно shop.example, а не прокси. Прокси в этой схеме не может подменить сертификат, не вызвав ошибку у клиента.
CONNECT в HTTP/2 и HTTP/3
В HTTP/2 метод CONNECT сохранился, но работает внутри одного мультиплексированного соединения: каждый туннель это отдельный поток. Это позволяет держать десятки туннелей через одно TCP-соединение с прокси и экономить на рукопожатиях. Расширенный CONNECT (с псевдозаголовком :protocol) используется для WebSocket поверх HTTP/2. В HTTP/3 на базе QUIC появилась спецификация CONNECT-UDP, которая формально позволяет туннелировать UDP через HTTP-прокси. Однако в клиентских библиотеках это пока экзотика, и на практике, если вам нужен UDP через прокси, вы будете смотреть в сторону SOCKS5.
Чего CONNECT не умеет
- Кэшировать: содержимое туннеля непрозрачно.
- Модифицировать заголовки: их просто не видно.
- Мультиплексировать несколько целевых хостов через один туннель в HTTP/1.1: один CONNECT равен одному TCP-соединению.
- Передавать UDP в HTTP/1.1 и HTTP/2.
SOCKS5: рукопожатие, аутентификация и ATYP
SOCKS5 описан в RFC 1928, а его схема аутентификации по логину и паролю в RFC 1929. Обе спецификации умещаются на нескольких страницах, и это одно из преимуществ протокола: реализовать его с нуля несложно, а значит, реализаций много и они редко расходятся в трактовке.
SOCKS5 бинарный протокол. Никакого текста, только байты фиксированной структуры. Рассмотрим полный обмен для команды CONNECT.
Шаг 1: приветствие и выбор метода аутентификации
Клиент отправляет версию и список методов аутентификации, которые он поддерживает:
05 02 00 02
VER=5 NMETHODS=2 METHODS: 00 (без аутентификации), 02 (логин/пароль)Сервер выбирает один метод и отвечает двумя байтами:
05 02
VER=5 METHOD=02 (сервер требует логин/пароль)Если сервер ответит 05 FF, это означает «ни один из предложенных методов не подходит», и клиент обязан закрыть соединение. Именно так выглядит на уровне байтов ситуация, когда вы забыли указать пароль, а прокси Proxeon настроен на авторизацию по логину.
Шаг 2: аутентификация по RFC 1929
Если выбран метод 02, клиент отправляет:
01 04 75 73 65 72 04 70 61 73 73
VER=1 ULEN=4 UNAME="user" PLEN=4 PASSWD="pass"Обратите внимание: версия подпротокола здесь 01, а не 05. Это частый источник ошибок в самописных клиентах. Сервер отвечает:
01 00
VER=1 STATUS=00 (успех; любое другое значение означает отказ)Логин и пароль передаются открытым текстом. Если между вами и прокси недоверенная сеть, стоит помнить об этом. На практике соединение с прокси обычно идёт через собственный канал провайдера, и вопрос решается на уровне транспорта или заменой на авторизацию по IP.
Шаг 3: запрос соединения
Теперь самое важное сообщение:
05 01 00 03 0C 73 68 6F 70 2E 65 78 61 6D 70 6C 65 01 BB
VER=5 CMD=01 (CONNECT) RSV=00 ATYP=03 (домен)
LEN=12 ADDR="shop.example" PORT=0x01BB (443)Поле CMD принимает три значения: 01 CONNECT (исходящее TCP-соединение), 02 BIND (ожидание входящего соединения, практически не используется), 03 UDP ASSOCIATE (создание UDP-ретранслятора). Механику UDP ASSOCIATE и её подводные камни мы разобрали в отдельной статье про UDP в SOCKS5, здесь только зафиксируем: это единственный из двух протоколов, у которого UDP есть штатно.
ATYP: домен против IP
Поле ATYP определяет, в каком виде клиент передал адрес назначения:
- 0x01 IPv4: следующие 4 байта адрес;
- 0x03 доменное имя: один байт длины, затем имя без завершающего нуля;
- 0x04 IPv6: следующие 16 байт адрес.
Казалось бы, техническая деталь. На самом деле это одно из самых важных решений, которое принимает клиент, и вот почему.
Если клиент использует ATYP=0x01 или 0x04, значит, он сам выполнил DNS-резолв перед отправкой запроса. Ваша машина обратилась к своему DNS-серверу, получила адрес и передала прокси уже готовый IP. Последствия:
- DNS-запрос ушёл через вашу локальную сеть и виден вашему провайдеру или администратору;
- вы получили тот IP, который DNS выдал для вашего региона; для сайтов за CDN это означает, что прокси, стоящий в другой стране, будет обращаться к «чужому» edge-серверу, что замедляет соединение и может выглядеть аномально;
- если ваша машина не имеет IPv6, вы никогда не получите AAAA-запись и не воспользуетесь IPv6-маршрутом прокси, даже если он есть;
- если DNS в вашей сети ведёт себя нестандартно, прокси получит неверный адрес, и вы будете долго искать причину.
Если клиент использует ATYP=0x03, резолв выполняет прокси. Он использует свою DNS-инфраструктуру, получает адрес, релевантный своему местоположению, и ваша локальная сеть не видит, к каким доменам вы обращаетесь. Для задач с геопривязкой это критично: смысл прокси в определённой стране частично теряется, если целевой сервер выбирается по DNS вашей домашней сети.
Как заставить клиент передавать домен? Зависит от клиента. В curl и Python-библиотеках за это отвечает выбор схемы socks5 против socks5h, и это тема отдельного разбора. Здесь важно понимать причину: буква h означает «hostname» и включает ATYP=0x03. Без неё библиотека резолвит имя локально.
Шаг 4: ответ сервера
05 00 00 01 C0 A8 01 0A 1F 90
VER=5 REP=00 (успех) RSV=00 ATYP=01 BND.ADDR=192.168.1.10 BND.PORT=8080Поле REP содержит код результата. Полезно знать их наизусть при отладке:
- 00 успех;
- 01 общая ошибка сервера;
- 02 соединение запрещено правилами;
- 03 сеть недостижима;
- 04 хост недостижим;
- 05 соединение отклонено целевым сервером;
- 06 истёк TTL;
- 07 команда не поддерживается;
- 08 тип адреса не поддерживается.
Код 08 встречается на старых или упрощённых реализациях, которые не поддерживают ATYP=0x03 или IPv6. Proxeon поддерживает все три типа адресов.
Почему SOCKS5 не разбирает содержимое
После ответа REP=00 SOCKS5-протокол закончился. Всё, что клиент пишет дальше, прокси перекладывает в целевое соединение без анализа. Это не ограничение реализации, а свойство дизайна. У SOCKS5 нет ни понятия «запрос», ни понятия «заголовок». Он не знает, что такое HTTP, IMAP или TLS. Ему передали адрес и порт, он соединил две трубы.
Из этого вытекает несколько практических следствий:
- SOCKS5 не может кэшировать: он не понимает, где заканчивается один ответ и начинается другой;
- SOCKS5 не может добавлять заголовки или подменять содержимое; максимум, что он может, это закрыть соединение;
- SOCKS5 не может фильтровать по URL, только по хосту и порту;
- SOCKS5 одинаково хорошо работает с любым TCP-протоколом, включая тот, который вы придумали вчера.
Полное рукопожатие SOCKS5 на Python
import socket, struct
def socks5_connect(proxy, user, pwd, host, port):
s = socket.create_connection(proxy)
s.sendall(b"\x05\x02\x00\x02")
ver, method = s.recv(2)
if method == 0x02:
u, p = user.encode(), pwd.encode()
s.sendall(b"\x01" + bytes([len(u)]) + u + bytes([len(p)]) + p)
if s.recv(2)[1] != 0:
raise RuntimeError("auth failed")
elif method != 0x00:
raise RuntimeError("no acceptable auth method")
h = host.encode()
s.sendall(b"\x05\x01\x00\x03" + bytes([len(h)]) + h + struct.pack("!H", port))
reply = s.recv(4)
if reply[1] != 0:
raise RuntimeError(f"connect failed, REP={reply[1]}")
atyp = reply[3]
s.recv({1: 4, 4: 16}.get(atyp, 0) if atyp != 3 else s.recv(1)[0])
s.recv(2)
return s
sock = socks5_connect(("gate.proxeon.net", 1080), "user", "pass", "shop.example", 443)
# дальше sock можно обернуть в ssl.wrap_socket или передать любому протоколуТридцать строк, и у вас работающий SOCKS5-клиент, который передаёт домен (ATYP=0x03) и оставляет резолв прокси-серверу. Именно эта простота делает SOCKS5 стандартом де-факто для программируемого доступа.
Сравнение по критериям: где каждый выигрывает
Теперь, когда механика обоих протоколов разобрана до байтов, сравнение перестаёт быть спором о вкусах и становится перечнем измеримых различий.
Не-HTTP протоколы
SOCKS5 работает с любым TCP-протоколом штатно: команда CONNECT, хост, порт, готово. HTTP-прокси тоже может через CONNECT, но с оговорками: клиент должен уметь отправлять CONNECT для не-HTTP трафика (почтовые клиенты умеют, большинство CLI-инструментов нет), а прокси должен разрешать нужный порт. Победитель: SOCKS5.
UDP
У SOCKS5 есть UDP ASSOCIATE. У HTTP-прокси в версиях 1.1 и 2 нет ничего, а CONNECT-UDP из HTTP/3 практически не поддерживается клиентами. Если задача включает DNS-запросы напрямую, QUIC, голосовые протоколы, игровой трафик, выбора нет. Победитель: SOCKS5, с оговоркой, что не всякий SOCKS5-сервер включает UDP, уточняйте в документации тарифа.
Накладные расходы на установление соединения
Считаем в раунд-трипах (RTT) между клиентом и прокси, поверх самого TCP-рукопожатия:
- HTTP-прокси, прозрачный режим, без авторизации: 0 дополнительных RTT, запрос уходит сразу;
- HTTP CONNECT с авторизацией в первом запросе: 1 RTT (CONNECT, ответ 200);
- SOCKS5 без авторизации: 2 RTT (приветствие, запрос);
- SOCKS5 с логином и паролем: 3 RTT (приветствие, аутентификация, запрос).
В байтах разница обратная: полное SOCKS5-рукопожатие с авторизацией укладывается примерно в 40 байт, а CONNECT с заголовками Host, Proxy-Authorization и User-Agent легко занимает 150 и больше. Но в реальных задачах решает RTT, а не байты. При задержке до прокси 50 мс SOCKS5 с авторизацией добавляет 150 мс к каждому новому соединению против 50 мс у CONNECT. Если клиент переиспользует соединения (keep-alive, пулы), это единовременная плата. Если каждый запрос открывает новый сокет, разница накапливается. Победитель по RTT: HTTP. Способ сократить разрыв для SOCKS5: авторизация по IP, которая убирает один RTT.
Кэширование
Только HTTP-прокси в прозрачном режиме. Не CONNECT, не SOCKS5. При этом кэшировать может только незашифрованный трафик, которого сегодня мало, поэтому этот критерий из решающего превратился в нишевый. Он актуален для внутренних сборочных систем, зеркал пакетов, повторяющихся запросов к API без TLS внутри доверенного контура. Победитель: HTTP, но с узкой областью применимости.
Логирование
Этот пункт часто понимают неверно. Что может записать в лог прокси в каждом режиме?
- HTTP прозрачный: полный URL, метод, заголовки, при желании тело; статус ответа; объёмы.
- HTTP CONNECT: хост и порт из строки CONNECT; время; объёмы; при желании SNI из ClientHello.
- SOCKS5 с ATYP=0x03: доменное имя и порт; время; объёмы; при желании SNI.
- SOCKS5 с ATYP=0x01/0x04: только IP и порт; домен прокси не знает; время; объёмы; SNI.
Для зашифрованного трафика CONNECT и SOCKS5 дают посреднику одинаковую видимость. Разница появляется только там, где SOCKS5-клиент передаёт IP вместо домена, и тогда прокси знает даже меньше. Но и целевой сервер при этом получает запрос из «неправильного» региона, см. раздел про ATYP. Ничья с нюансами.
Диагностика ошибок
HTTP-прокси отвечает человекочитаемыми кодами: 407 говорит об авторизации, 403 о запрете, 502 о недоступности цели, 504 о таймауте. Некоторые реализации добавляют тело с пояснением. SOCKS5 отвечает одним байтом REP, и не всякая библиотека переводит его в понятное сообщение. При отладке в незнакомом окружении HTTP-прокси диагностировать проще. Победитель: HTTP.
Мультиплексирование
HTTP/2-прокси позволяет провести множество CONNECT-туннелей через одно соединение. SOCKS5 требует отдельного TCP-соединения на каждую цель. Для клиентов с сотнями параллельных соединений это заметно снижает нагрузку на сетевой стек и прокси. Но поддержка HTTP/2 к прокси в клиентах пока фрагментарна. Потенциальный победитель: HTTP, фактический паритет.
Возможность вмешательства в трафик
HTTP-прокси в прозрачном режиме может изменить всё. В режиме CONNECT и в SOCKS5 может только разорвать соединение. Для клиента, который хочет гарантий неизменности трафика, лучше всего SOCKS5 или CONNECT с TLS внутри. Победитель по предсказуемости: SOCKS5.
Аутентификация
Оба умеют логин и пароль. HTTP дополнительно поддерживает схемы Digest, NTLM, Negotiate, что важно для корпоративных сред. SOCKS5 формально имеет метод GSSAPI, но в коммерческих прокси он практически не встречается. Для работы с сервисом вроде Proxeon это не имеет значения: там используется Basic либо белый список IP.
Что выбрать под задачу: таблица
Соберём выводы в рабочий инструмент. Таблица исходит из того, что оба режима доступны на одном IP, как это устроено в Proxeon, и вопрос только в том, какой порт указать.
| Задача | Рекомендуемый протокол | Почему |
|---|---|---|
| Браузер для ручной работы или тестирования | HTTP (с CONNECT для HTTPS) | Все браузеры поддерживают HTTP-прокси с авторизацией через системные настройки или расширения; SOCKS5 с логином и паролем в Chromium-браузерах через системный прокси не работает, авторизация возможна только по IP |
| HTTP-клиент, парсер, сборщик данных на Python, Node.js, Go | SOCKS5 с передачей домена (ATYP=0x03) | Резолв на стороне прокси даёт правильные региональные адреса CDN, библиотеки поддерживают оба режима, а SOCKS5 не рискует вмешаться в заголовки |
| Парсер с большим количеством коротких соединений без keep-alive | HTTP CONNECT или SOCKS5 с авторизацией по IP | Каждый RTT рукопожатия множится на число соединений; CONNECT экономит 1-2 RTT против SOCKS5 с паролем |
| Почтовый клиент (IMAP, SMTP, POP3) | SOCKS5 | Почтовые протоколы не HTTP; десктопные клиенты поддерживают SOCKS5 напрямую, а через HTTP-прокси потребовали бы CONNECT на нестандартные порты |
| SSH, клиенты баз данных, RDP, любой TCP-протокол | SOCKS5 | Штатная поддержка в OpenSSH через ProxyCommand или ProxyJump-совместимые обёртки, в большинстве клиентов БД нативно; HTTP CONNECT работает не везде |
| Приложения, использующие UDP: DNS-клиенты, QUIC, голос | SOCKS5 с UDP ASSOCIATE | Единственный из двух протоколов, у которого UDP есть в спецификации |
| Кэширующий прокси для внутренних сборок и зеркал пакетов по HTTP | HTTP прозрачный | Только он понимает семантику ответов и может их кэшировать |
| Корпоративное приложение, умеющее только системный прокси Windows | HTTP | WinHTTP и системные настройки Windows работают с HTTP-прокси; SOCKS-поддержка там ограничена и без авторизации |
| Мобильное приложение под Android или iOS в тестовой среде | HTTP | Системные настройки Wi-Fi обеих платформ поддерживают только HTTP-прокси; SOCKS5 потребует проксификатора на уровне приложения |
| Собственный софт с прямой работой с сокетами | SOCKS5 | Реализация 30 строк, бинарный формат без парсинга, поддержка любого протокола поверх, явный контроль над местом резолва |
| Инструменты командной строки: curl, wget, git | HTTP для wget; SOCKS5 или HTTP для curl и git | wget не поддерживает SOCKS вообще; curl и git умеют оба режима |
| Мониторинг доступности сайтов из разных регионов | SOCKS5 с ATYP=0x03 | Нужно, чтобы DNS-резолв шёл из региона прокси, иначе проверяется не тот edge-сервер |
| Отладка, когда что-то не работает и непонятно почему | HTTP | Коды 407, 403, 502, 504 понятнее байта REP, а curl -v показывает весь диалог с прокси |
Алгоритм выбора за четыре шага
- Определите протокол внутри. Если это не HTTP и не HTTPS, берите SOCKS5 и не раздумывайте.
- Проверьте, что умеет клиент. Откройте его документацию по ключевым словам socks5, proxy, CONNECT. Если SOCKS5 нет или он без авторизации, выбор сделан за вас.
- Решите, где должен резолвиться домен. Если важен регион (CDN, геозависимый контент, мониторинг), берите SOCKS5 с передачей домена или HTTP CONNECT: в обоих случаях резолвит прокси.
- Оцените профиль соединений. Много коротких соединений без пула: смотрите на RTT рукопожатия, выбирайте HTTP CONNECT или включайте авторизацию по IP.
Совместимость в популярных клиентах и библиотеках
Теория заканчивается там, где начинаются реальные клиенты. Ниже разбор поведения самых распространённых инструментов по состоянию на 2026 год. Проверяйте актуальные версии: поведение меняется от релиза к релизу.
curl
Поддерживает всё. Схемы в параметре -x или переменных окружения: http://, https:// (TLS до самого прокси), socks4://, socks4a://, socks5://, socks5h://. Разница socks5 и socks5h описана в отдельной статье, здесь запомните: для резолва на прокси нужна socks5h.
curl -x socks5h://user:pass@gate.proxeon.net:1080 https://shop.example/
curl -x http://user:pass@gate.proxeon.net:8080 https://shop.example/Переменные окружения http_proxy, https_proxy, all_proxy читаются автоматически; all_proxy принимает и SOCKS-схемы.
wget
Только HTTP-прокси. SOCKS не поддерживается ни в каком виде. Если нужен wget через SOCKS5, потребуется системный проксификатор.
Python: requests
HTTP-прокси из коробки. Для SOCKS5 нужен дополнительный пакет PySocks (устанавливается как requests[socks]).
import requests
proxies = {
"http": "socks5h://user:pass@gate.proxeon.net:1080",
"https": "socks5h://user:pass@gate.proxeon.net:1080",
}
r = requests.get("https://shop.example/api/items", proxies=proxies, timeout=15)
print(r.status_code, r.headers.get("cf-ray"))Для HTTPS через HTTP-прокси requests автоматически использует CONNECT. Для HTTP через HTTP-прокси используется абсолютная форма.
Python: httpx
HTTP-прокси из коробки, SOCKS5 через пакет socksio (httpx[socks]). Схема socks5:// в httpx передаёт домен прокси-серверу. Поддерживает async, что делает его удобным для параллельных задач.
import httpx, asyncio
async def main():
async with httpx.AsyncClient(proxy="socks5://user:pass@gate.proxeon.net:1080") as c:
r = await c.get("https://shop.example/")
print(r.status_code)
asyncio.run(main())Python: aiohttp
HTTP-прокси нативно. SOCKS5 через пакет aiohttp-socks с классом ProxyConnector, у которого параметр rdns управляет местом резолва.
Node.js: fetch и undici
Встроенный fetch в Node.js использует undici, где есть ProxyAgent для HTTP-прокси. Для SOCKS5 применяется отдельный агент из экосистемы, например socks-proxy-agent для http/https модулей.
import { ProxyAgent, fetch } from "undici";
const agent = new ProxyAgent({
uri: "http://gate.proxeon.net:8080",
token: "Basic " + Buffer.from("user:pass").toString("base64"),
});
const res = await fetch("https://shop.example/", { dispatcher: agent });
console.log(res.status);Go
Стандартный net/http поддерживает HTTP-прокси через Transport.Proxy и переменные окружения. Начиная с Go 1.13 схема socks5:// в HTTP_PROXY тоже принимается стандартной библиотекой. Для тонкого контроля используется пакет golang.org/x/net/proxy.
package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
u, _ := url.Parse("socks5://user:pass@gate.proxeon.net:1080")
tr := &http.Transport{Proxy: http.ProxyURL(u)}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://shop.example/")
if err != nil {
panic(err)
}
fmt.Println(resp.Status)
}В Go схема socks5 передаёт домен прокси: локальный резолв не выполняется.
Java
HTTP-прокси через системные свойства http.proxyHost, https.proxyHost или объект Proxy с типом Type.HTTP. SOCKS через socksProxyHost и Proxy.Type.SOCKS. Авторизация через класс Authenticator. Начиная с JDK 8u111 схема Basic для HTTPS через CONNECT по умолчанию отключена свойством jdk.http.auth.tunneling.disabledSchemes, его нужно очистить, иначе получите 407 без объяснений. Это одна из самых частых причин обращений в поддержку.
.NET
HttpClient с SocketsHttpHandler поддерживает HTTP-прокси через WebProxy. Поддержка SOCKS4, SOCKS4a и SOCKS5 появилась в .NET 6 и включается той же конструкцией WebProxy с адресом вида socks5://host:port.
Браузеры
Chromium-браузеры используют системные настройки прокси или флаг --proxy-server. HTTP-прокси с авторизацией работает: браузер показывает диалог логина. SOCKS5 через системные настройки работает без авторизации, логин и пароль передать нельзя. Для SOCKS5 с паролем нужно расширение с API proxy или авторизация по IP. Firefox имеет собственные настройки прокси, поддерживает SOCKS5 и опцию «Proxy DNS when using SOCKS v5», которая включает ATYP=0x03. Авторизация для SOCKS5 в Firefox также штатно не предусмотрена.
Почтовые клиенты
Thunderbird использует настройки прокси, аналогичные Firefox, и умеет SOCKS5 для IMAP и SMTP. Многие другие десктопные почтовые клиенты имеют собственный раздел SOCKS5-прокси в настройках учётной записи. Через HTTP-прокси почта работает только если клиент умеет отправлять CONNECT на порты 993 и 465, что встречается редко.
Системные проксификаторы
Для приложений без собственных настроек прокси существуют программы, перехватывающие сетевые вызовы на уровне системы и перенаправляющие их в SOCKS5 или HTTP-прокси. Практически все они предпочитают SOCKS5 как транспорт именно потому, что он не зависит от протокола внутри. Если ваша задача включает такой инструмент, готовьте порт SOCKS5.
Чек-лист совместимости
- Клиент умеет SOCKS5? Умеет ли он передавать логин и пароль в SOCKS5?
- Клиент резолвит домен сам или отдаёт прокси? Есть ли настройка remote DNS?
- Клиент корректно обрабатывает 407 и повторяет запрос с авторизацией?
- Клиент использует CONNECT для HTTPS или пытается отправить абсолютный URI с https-схемой (так делают некоторые древние библиотеки, и это не работает)?
- Клиент переиспользует соединения к прокси или открывает новое на каждый запрос?
Кейсы из инженерной практики
Цифры ниже типичны для описанных сценариев и приведены для понимания порядка эффекта, а не как гарантированный результат.
Кейс 1: мониторинг витрин из разных регионов
Команда следила за доступностью и ценами на собственных региональных витринах через прокси из нескольких стран. Использовали Python и requests со схемой socks5://. Периодически метрики показывали «неправильную» цену для региона, хотя витрина работала корректно. Причина: библиотека резолвила домен локально, в стране офиса, и передавала прокси уже готовый IP edge-сервера CDN. Прокси из другой страны честно соединялся с этим адресом, а CDN отдавал контент, определив регион по своему узлу, а не по IP клиента. Замена схемы на socks5h перенесла резолв на прокси. Доля аномальных измерений упала практически до нуля, а медианное время ответа снизилось примерно на треть за счёт того, что прокси стал ходить на ближайший к себе узел CDN.
Кейс 2: парк сборщиков данных с короткими соединениями
Сервис агрегации открытых цен выполнял до нескольких сотен тысяч запросов в сутки через SOCKS5 с логином и паролем, открывая новое соединение на каждый запрос. Профилирование показало, что три RTT рукопожатия на соединение при задержке до прокси около 40 мс давали 120 мс накладных расходов на каждый запрос, около четверти всего времени. Два изменения: включили пул соединений в HTTP-клиенте и перешли на авторизацию по IP, убрав один RTT. Суммарное время прохода по списку сократилось примерно на 30 процентов без изменения количества прокси. Протокол при этом оставили SOCKS5, потому что смена на HTTP CONNECT дала бы меньший выигрыш, чем пул.
Кейс 3: почтовые ящики и IMAP
Служба поддержки разворачивала десктопный почтовый клиент для нескольких региональных представительств, где каждый ящик должен был подключаться к почтовому серверу через IP определённого региона. Первая попытка через HTTP-прокси провалилась: клиент не умел CONNECT для IMAP. Переключение на порт SOCKS5 в Proxeon решило задачу за минуты, потому что клиент имел нативную настройку SOCKS5 для каждой учётной записи. Никакого дополнительного софта.
Кейс 4: Java-приложение и загадочный 407
Корпоративный интегратор подключал Java-сервис к внешнему API через HTTP-прокси с Basic-авторизацией. Прокси стабильно возвращал 407, хотя учётные данные были верны, а curl с теми же параметрами работал. Причина: начиная с определённого обновления JDK, Basic-аутентификация для CONNECT-туннелей отключена по умолчанию. Один флаг JVM с очисткой jdk.http.auth.tunneling.disabledSchemes решил проблему. Здесь пригодилось именно то, что HTTP-прокси отвечает читаемым кодом: код 407 сразу указал направление поиска, тогда как SOCKS5 в аналогичной ситуации вернул бы 05 FF, и без знания протокола понять это было бы сложнее.
Частые заблуждения
- «SOCKS5 безопаснее HTTP-прокси». Для зашифрованного трафика оба протокола дают посреднику одинаковую видимость: хост, порт, тайминги, объёмы, SNI. Безопасность содержимого обеспечивает TLS, а не протокол прокси. Разница есть только для незашифрованного HTTP, где прозрачный HTTP-прокси видит всё.
- «HTTP-прокси не работает с HTTPS». Работает через CONNECT. Это стандартный и повсеместный механизм, именно так все браузеры ходят на HTTPS-сайты через корпоративные прокси.
- «SOCKS5 быстрее, потому что бинарный». На установление соединения SOCKS5 с авторизацией тратит больше RTT, чем HTTP CONNECT. На передаче данных оба не добавляют ничего: после рукопожатия это чистая TCP-труба в обоих случаях. Скорость определяется каналом прокси, а не протоколом.
- «CONNECT нужен только для 443 порта». Стандарт не ограничивает порт. Ограничения вводит конфигурация конкретного прокси.
- «SOCKS5 всегда резолвит домен на прокси». Только если клиент передаёт ATYP=0x03. Многие библиотеки по умолчанию резолвят локально и передают IP.
- «HTTP-прокси всегда добавляет X-Forwarded-For и раскрывает мой IP». Это поведение конкретных корпоративных настроек, а не свойство протокола. Коммерческие прокси такие заголовки не добавляют, а в режиме CONNECT добавить их физически невозможно.
- «Прокси видит мой пароль от прокси в открытом виде, значит и от сайта тоже». Пароль от прокси передаётся прокси и по стандарту не пересылается дальше. Пароль от сайта внутри TLS-туннеля прокси не видит.
- «Раз SOCKS5 не разбирает содержимое, его нельзя ограничить». Прокси может ограничивать по целевому хосту, порту, объёму, скорости и количеству соединений. Просто не по URL.
- «HTTP и SOCKS5 порты у одного провайдера это разные серверы». Как правило, это один сервер и один выходной IP, отличается только протокол на входе. В Proxeon именно так.
- «В браузере SOCKS5 с паролем настраивается так же, как HTTP». Нет, системные настройки Chromium и Firefox не передают учётные данные в SOCKS5. Нужна авторизация по IP или расширение.
FAQ
Целевой сайт может определить, пришёл ли я через HTTP-прокси или через SOCKS5?
Нет. Целевой сервер видит только второе соединение, от прокси к себе, и оно в обоих случаях представляет собой обычный TCP от IP-адреса прокси. Единственное исключение: прозрачный HTTP-прокси, который добавляет заголовки Via или X-Forwarded-For. В режиме CONNECT и в SOCKS5 это невозможно.
Если я использую HTTP-прокси для HTTPS, прокси может подсмотреть или подменить содержимое?
Только если он выполнит перехват TLS с подменой сертификата, и тогда ваш клиент увидит ошибку проверки сертификата, если только вы не установили доверенный корневой сертификат этого прокси вручную. В штатной работе после CONNECT прокси видит зашифрованный поток и не может ни прочитать, ни изменить его содержимое.
Почему SOCKS5 с паролем не работает в Chrome, а HTTP-прокси с паролем работает?
Реализация сетевого стека Chromium поддерживает диалог авторизации для HTTP-прокси через механизм 407, но не реализует метод 0x02 из RFC 1929 для SOCKS5. Это решение разработчиков браузера, а не ограничение протокола. Решение: авторизация по IP-адресу в личном кабинете Proxeon либо расширение, управляющее прокси через API.
Что делать, если прокси возвращает REP=05 в SOCKS5?
Код 05 означает, что целевой сервер отклонил TCP-соединение: порт закрыт, сервис не запущен, либо файрвол цели блокирует IP прокси. Проверьте, что вы передали правильный порт, и попробуйте другой прокси-адрес. Сам прокси при этом работает корректно, проблема на второй половине пути.
В чём разница между REP=02 в SOCKS5 и 403 у HTTP-прокси?
Семантически это одно и то же: прокси отказался устанавливать соединение по своим правилам. Обычно это означает, что целевой порт или хост запрещён политикой прокси. У HTTP-прокси в теле ответа 403 иногда есть пояснение, у SOCKS5 только байт.
Можно ли использовать один и тот же логин и пароль для HTTP- и SOCKS5-порта?
В Proxeon да: учётная запись общая, отличается только порт и протокол. При смене протокола менять учётные данные не нужно.
Как понять, резолвит ли мой клиент домен локально или на прокси?
Самый надёжный способ: запустить перехват трафика на своём интерфейсе и посмотреть, уходит ли DNS-запрос к целевому домену перед подключением к прокси. Более простой: временно указать в hosts-файле для целевого домена заведомо неверный адрес. Если запрос через прокси продолжает работать, резолвит прокси. Если ломается, резолвит клиент.
Стоит ли использовать HTTP/2 к прокси, если библиотека это поддерживает?
Если у вас много параллельных соединений к разным целям и клиент действительно мультиплексирует CONNECT-потоки, выигрыш будет заметен: меньше TCP-соединений, меньше рукопожатий. Но поддержка этой возможности в клиентах и прокси-серверах пока неравномерна. Проверяйте документацию своего клиента и уточняйте, поддерживает ли HTTP/2 на входе ваш тариф.
Почему в HTTP-прокси абсолютный URI, если есть заголовок Host?
Стандарт HTTP/1.1 требует от клиента использовать абсолютную форму при обращении к прокси, чтобы прокси однозначно понимал, что запрос нужно переслать, а не обработать локально. Заголовок Host сохраняется потому, что прокси перешлёт запрос целевому серверу уже в origin-form, и Host там обязателен. Дублирование это плата за совместимость.
Что важнее для парсинга: HTTP или SOCKS5?
Для HTTPS-целей разницы в видимости нет, разница в поведении библиотеки. Если библиотека нормально работает с SOCKS5 и передаёт домен, берите SOCKS5: он не рискует вмешаться в заголовки и даёт правильный региональный резолв. Если библиотека с SOCKS5 капризничает или у вас много коротких соединений без пула, HTTP CONNECT ничем не хуже. Главный совет: не открывайте новое соединение с прокси на каждый запрос, это дороже любого выбора протокола.
Заключение
Два порта в личном кабинете это не маркетинговая пара «обычный и продвинутый». Это два разных языка общения с одной и той же машиной. HTTP-прокси говорит на языке запросов и ответов, понимает семантику, может кэшировать и объясняет ошибки читаемыми кодами, а для всего непонятного у него есть CONNECT, превращающий его в TCP-туннель. SOCKS5 говорит на языке «хост и порт», не разбирает содержимое, поддерживает любой TCP-протокол и UDP, и позволяет явно управлять тем, где резолвится домен.
Для зашифрованного трафика оба протокола дают посреднику одинаковую видимость. Выбор между ними определяется не безопасностью, а тремя практическими вещами: что умеет ваш клиент, какой протокол внутри и где вы хотите резолвить имена.
Что сделать сейчас
- Определите протокол внутри вашей задачи. Не HTTP: сразу SOCKS5.
- Проверьте в документации клиента поддержку SOCKS5 с авторизацией и опцию удалённого резолва.
- Если работаете с геозависимыми ресурсами, убедитесь, что домен уходит прокси: socks5h, remote DNS, ATYP=0x03 или HTTP CONNECT.
- Включите пул соединений или keep-alive к прокси. Это даст больше, чем любая смена протокола.
- Если клиент не умеет передавать логин в SOCKS5, настройте авторизацию по IP в кабинете Proxeon.
- При отладке начинайте с curl -v: он покажет весь диалог с прокси и сразу отделит проблему клиента от проблемы сети.
И напоследок. Оба протокола старше большинства инженеров, которые ими пользуются, и оба до сих пор работают без принципиальных изменений. Это редкий случай, когда простота дизайна победила. Понимая, что именно происходит в первых сорока байтах соединения, вы перестаёте выбирать порт наугад и начинаете выбирать инструмент.