SSLError через прокси в requests и urllib3

Защищённое соединение не установилось: либо программа попыталась говорить TLS с прокси, который ждёт обычный HTTP, либо сертификат сайта не прошёл проверку.

Обновлено · Редакция Prokso

Коротко
  • Ошибка wrong version number через прокси почти всегда означает схему https:// в строке HTTP-прокси
  • CERTIFICATE_VERIFY_FAILED касается сертификата сайта: прокси в туннеле CONNECT шифрование не меняет
  • Пишите http:// для порта 823, обновите certifi и не отключайте проверку через verify=False

Что означает ошибка

Когда requests открывает https-сайт через HTTP-прокси, он сначала просит прокси открыть туннель методом CONNECT. Дальше прокси только передаёт байты, а шифрованное соединение устанавливается между вашим кодом и сайтом. Поэтому сертификат, который проверяет requests, прислал сайт, а не прокси.

Самая частая ошибка здесь — строка прокси со схемой https://. Тогда urllib3 пытается установить TLS с самим прокси, а порт 823 ждёт обычный HTTP. В ответ приходит не TLS, и OpenSSL пишет [SSL: WRONG_VERSION_NUMBER] wrong version number. В текущей urllib3 2.x это обёрнуто в ProxyError с подсказкой Your proxy appears to only use HTTP and not HTTPS, try changing your proxy URL to be HTTP.

CERTIFICATE_VERIFY_FAILED — другая ситуация: TLS с сайтом начался, но цепочка сертификатов не прошла проверку. Через туннель CONNECT причины те же, что и без прокси: устаревший набор корневых сертификатов, подмена сертификата антивирусом или корпоративной сетью, переменные REQUESTS_CA_BUNDLE или CURL_CA_BUNDLE, указывающие на другой файл.

Причины

  • Схема https:// для HTTP-прокси. Строка https://ЛОГИН:ПАРОЛЬ@gw.prokso.com:823 заставляет библиотеку шифровать соединение с прокси, и появляется wrong version number.
  • Схема http:// на порту SOCKS5. Порт 824 работает только по протоколу SOCKS5. HTTP-запрос на него не получит HTTP-ответа, и текст ошибки будет непонятным.
  • Перехват HTTPS. Антивирус или корпоративный шлюз подставляет свой сертификат, и requests сообщает CERTIFICATE_VERIFY_FAILED, часто с текстом self-signed certificate in certificate chain.
  • Устаревший certifi или другой CA-файл. Requests берёт корневые сертификаты из пакета certifi, а переменная REQUESTS_CA_BUNDLE может подменить этот набор.
  • Проблема с сертификатом самого сайта. Сертификат просрочен или выдан на другой домен. Тогда ошибка будет и без прокси.

Как исправить

  1. Для порта 823 и портов 10000–20000 в режиме HTTP пишите схему http://: 'https': 'http://ЛОГИН:ПАРОЛЬ@gw.prokso.com:823'. Ключ 'https' в словаре означает схему сайта, а не прокси.
  2. Для SOCKS5 используйте socks5h://ЛОГИН:ПАРОЛЬ@gw.prokso.com:824 и установите зависимости SOCKS. Примеры для обоих протоколов есть в инструкции Python requests, а все порты и форматы строки — в справочнике о шлюзе.
  3. Обновите пакеты командой pip install -U requests certifi и проверьте, не заданы ли REQUESTS_CA_BUNDLE и CURL_CA_BUNDLE: env | grep CA_BUNDLE.
  4. Если работаете в корпоративной сети или с антивирусом, который сканирует HTTPS, передайте путь к их корневому сертификату: verify='/путь/к/ca.pem'.
  5. Не ставьте verify=False. По документации requests этот параметр касается только сертификата сайта: wrong version number от прокси он не уберёт, а CERTIFICATE_VERIFY_FAILED только спрячет, оставив соединение беззащитным перед подменой.

Как проверить, что всё заработало

Запустите requests.get('https://prokso.com/ip', proxies=proxies, timeout=30) с включённой проверкой сертификатов. Если получили JSON с IP прокси, туннель и TLS работают. Для сравнения откройте страницу Мой IP в браузере через тот же прокси: если там ошибки нет, а в коде есть, дело в настройках Python.

Диагностика за 2 минуты

Сначала вставьте строку в проверку прокси. Если там прокси работает, причина в программе или её настройках. Если нет — проверьте строку из терминала:

curl -v -x "http://ЛОГИН:ПАРОЛЬ@gw.prokso.com:823" https://api.ipify.org
  • Строка < HTTP/1.1 407 сразу после CONNECT — отвечает прокси. Название после кода, например NO_USER, подсказывает причину.
  • Прокси ответил на CONNECT кодом 200, а дальше пришёл другой код — прокси работает, этот ответ дал сайт.
  • Никакого ответа, только тайм-аут — соединение не дошло до прокси: проверьте хост, порт и сеть.

Инструкции, где встречается эта ошибка

Вопросы и ответы

Может ли прокси Prokso подменить сертификат сайта?

Нет. В туннеле CONNECT шифрование устанавливается между вашей программой и сайтом, а прокси передаёт уже зашифрованные данные. Подробнее — на странице <a href="/ru/errors/ssl-certificate-errors">ошибки SSL и сертификатов</a>.

Сайт на https://, значит, и прокси должен быть https://?

Нет. Схема адреса сайта и схема строки прокси — разные вещи. Сайт может быть на https://, а соединение с прокси на порту 823 — обычным http://, внутри которого идёт шифрованный туннель.

Почему ошибка только в Python, а браузер открывает сайт?

У браузера своё хранилище сертификатов, а requests пользуется пакетом certifi или файлом из переменной REQUESTS_CA_BUNDLE. Обновите certifi и проверьте переменные окружения.

Резидентские $1.59, мобильные $2.50, серверные $0.65 за 1 ГБ

Регистрация за минуту, доступы сразу после оплаты.

Создать аккаунт