403 через прокси: отказал сайт, отказал прокси или дело вообще не в адресе
403 — код, который может прийти из двух разных мест: от прокси, который не пустил вас дальше, и от целевого сайта, который не пустил вас к себе. Лечение у этих случаев противоположное, а по самому коду они не различаются. Разбираемся, где различие видно, где его не видно принципиально, и в каких случаях смена адреса не поможет вообще.
Когда 403 вообще можно приписать источнику
Различить надёжно можно только при работе по HTTPS, и вот почему. Для HTTPS клиент сначала просит прокси открыть туннель командой CONNECT. По RFC 9110 любой ответ на CONNECT, кроме успешного, означает, что туннель не установлен: то есть 403 на этом этапе сформировал именно прокси, до сайта запрос не дошёл. Если же туннель открылся, всё, что придёт внутри него, сформировал сайт — прокси в зашифрованный поток вставить ничего не может.
Как посмотреть код именно от прокси
У curl для этого есть отдельное поле вывода: http_connect — код, найденный в последнем ответе прокси на запрос CONNECT. Смотреть надо его, а не код выхода утилиты: номер кода выхода менялся между версиями curl, а это поле — нет.
# http_code -> что ответил сайт
# http_connect -> что ответил прокси на CONNECT
curl -x http://ШЛЮЗ:ПОРТ https://example.com -o /dev/null \
-w 'connect=%{http_connect} site=%{http_code}\n'
# connect=200 site=403 -> прокси пустил, 403 от сайта
# connect=403 site=000 -> прокси не пустил, до сайта не дошлиТекст ошибки стоит знать в двух вариантах: современный curl пишет «CONNECT tunnel failed, response 403», а строку «Received HTTP code 403 from proxy after CONNECT» он выдавал до версии 7.87.0 от декабря 2022 года — под неё написана половина найденных в поиске инструкций.
Коды Cloudflare живут в теле ответа
Если целевой сайт за Cloudflare, самое полезное — четырёхзначный код вида 1xxx. В документации сказано прямо: обычные коды вроде 403, 409 или 429 возвращаются в статусном заголовке ответа, а ошибки 1XXX появляются в HTML-теле. То есть grep по статусной строке их не найдёт, смотреть нужно в тело.
И обратный признак от самой Cloudflare: 403 без её брендированной страницы означает, что отказ пришёл от сервера сайта, а не от Cloudflare. Правда, полагаться на это как на правило нельзя — Cloudflare отдаёт и неоформленную страницу 403, и произвольный код, если владелец сайта настроил его в своём правиле.
Что означает каждый код
- 1005 — забанен ASN, то есть автономная система, к которой относится адрес. Это отказ уровня сети, а не конкретного адреса.
- 1006, 1007, 1008 и 1106 — Cloudflare описывает их под одним заголовком «доступ запрещён: ваш IP-адрес забанен» и с одной причиной: клиент заблокирован клиентом Cloudflare. Разных значений у этих номеров в документации нет.
- 1009 — забанена страна или регион. Меняется страной выхода, а не адресом внутри той же страны.
- 1010 — отказ по подписи браузера. Владелец сайта включил проверку целостности браузера; к адресу это отношения не имеет.
- 1020 — отказ по правилу файрвола Cloudflare. Не то же самое, что бан адреса: правило может смотреть на что угодно.
Когда смена адреса не поможет
Это главный практический вывод, и он против интуиции. Расширять пул адресов имеет смысл, только когда отказ привязан к адресу или сети: 1005 лечится другой автономной системой, 1006–1008 — другим адресом, 1009 — другой страной. А вот 1010 и 1020 к адресу не привязаны вовсе: первый смотрит на подпись браузера, второй — на правило, которое может проверять заголовки, путь или что угодно ещё. Купить больше адресов и получить тот же отказ — самый частый способ потратить деньги впустую.
Почему заголовки прокси — плохой тест
Совет «посмотрите, есть ли в ответе Via или X-Squid-Error» встречается часто, и он ненадёжен в обе стороны. Via прокси может не отправлять вовсе, может подставить псевдоним вместо имени, а администратор — вырезать заголовок настройками. X-Squid-Error существует только у Squid и тоже удаляется настройкой. Отсутствие этих заголовков не доказывает, что отвечал сайт, а их наличие не доказывает обратного для конкретного запроса.
Сюда же: прокси при отказе по своему списку доступа не обязан отдавать именно 403. Squid по умолчанию отдаёт 403, но настройкой это меняется на любой другой код, на редирект или на разрыв соединения без ответа вообще. А отказ по авторизации — это 407, отдельный код с отдельной причиной.
Коды, которые точно не про прокси
- 451 — отказ по юридическим требованиям, для российской аудитории чаще регуляторная блокировка, а не антибот.
- 421 — по RFC 9110 прокси не имеет права его формировать, поэтому 421 всегда пришёл с origin или шлюза сайта.
- 400 на CONNECT — сервер обязан отклонить запрос с пустым или неверным номером порта, обычно как раз этим кодом. То есть проверьте порт в строке подключения.
Когда дело всё-таки в адресах
Если отказ привязан к адресу или сети, помогает пул: ротационные IPv6 от 650 ₽ за 50 потоков, IPv4 от 1375 ₽ за 100. Если отказ по подписи браузера или по правилу — пул не поможет, и мы скажем это прямо.
Смотреть тарифыПрокси под эту задачу
Проверить нашими инструментами
Читайте также
- Ошибка 407 Proxy Authentication Required: почему прокси не пускает парсер407 возвращает прокси, а не целевой сайт. Пять причин по частоте, проверка одной командой и что делать, если софт умеет только ip:port.
- Ошибка 429 при парсинге: как считать паузы и ретраи, а не гадать429 — лимит на адрес, а не на аккаунт. Разбираем Retry-After, экспоненциальную задержку с джиттером и почему в Scrapy backoff работает иначе.
- Один шлюз вместо списка прокси: как настроить софт, который ждёт списокПарсеры считают масштаб числом прокси, а ротационный шлюз — это одна строка. Разбор по программам: где переключить режим, где продублировать строку и где честный ответ — купить список.
