Python запрашивает запросы.исключения.SSLError: [Errno 8] _ssl.c:504: EOF произошел с нарушением протокола

Я использую Ubuntu 12.10 с OpenSSL 1.0.1c, python 2.7.3, Requests 1.0.3 и 1.0. .4 (пробовал оба), и при попытке подключиться к сайту в переменной url со следующим кодом.

def SendInitialRequest(xmlmessage, redirecturl):
    url = 'https://centineltest.cardinalcommerce.com/maps/txns.asp'

    payload = 'cmpi_msg=' + ET.tostring(xmlmessage)
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
    }
    r = requests.post(url, data=payload, headers=headers, verify=None)
    print r.text

Выдает следующую ошибку:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "clams/libs/centinel/thinclient.py", line 134, in SendInitialRequest
    r = requests.post(url, data=payload, headers=headers, verify=None)
  File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/api.py", line 87, in post
    return request('post', url, data=data, **kwargs)
  File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/sessions.py", line 269, in request
    resp = self.send(prep, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
  File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/sessions.py", line 364, in send
    r = adapter.send(request, **kwargs)
  File "/home/jasonamyers/.virtualenv/clams/lib/python2.7/site-packages/requests/adapters.py", line 163, in send
    raise SSLError(e)
requests.exceptions.SSLError: [Errno 8] _ssl.c:504: EOF occurred in violation of protocol

Попытка подключения с помощью openssl возвращает следующее:

$ openssl s_client -connect centineltest.cardinalcommerce.com:443
CONNECTED(00000003)
140019346777760:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 226 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---

Если я заставлю его использовать tls1, он сработает (вывод усечен):

$ openssl s_client -tls1 -connect centineltest.cardinalcommerce.com:443
CONNECTED(00000003)
depth=2 C = US, O = "thawte, Inc.", OU = Certification Services Division, OU
verify error:num=20:unable to get local issuer certificate
verify return:0
---

Я видел множество отчетов об ошибках для этого; однако я не нашел способа обойти это с помощью библиотеки запросов python. Будем очень благодарны любой помощи.


person jasonamyers    schedule 31.12.2012    source источник
comment
Вы установили openssl через менеджер пакетов? Если да, то проверяли ли вы обновления? Я могу подключиться к этому сайту с помощью запросов.   -  person Thomas Orozco    schedule 31.12.2012
comment
Я установил openssl через менеджер пакетов, обновлений нет. Можете ли вы поделиться версиями всего, что вы используете? Также вы используете встроенный python или использовали pythonbrews и т. д. для создания собственного?   -  person jasonamyers    schedule 31.12.2012
comment
В моем случае ответ был таким: stackoverflow.com/a/34891294/5953624   -  person FrieBee    schedule 20.02.2016
comment
У меня была эта ошибка при попытке подключения к конечной точке HTTP с использованием HTTPS. Я просто изменил URL-адрес, и он работал нормально.   -  person fafl    schedule 24.07.2017


Ответы (10)


Репост сюда для других со страницы выдачи запросов:

Запросы не поддерживают это до версии 1. После версии 1 вы должны создать подкласс HTTPAdapter, например:

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager
import ssl

class MyAdapter(HTTPAdapter):
    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(num_pools=connections,
                                       maxsize=maxsize,
                                       block=block,
                                       ssl_version=ssl.PROTOCOL_TLSv1)

Когда вы это сделаете, вы можете сделать это:

import requests
s = requests.Session()
s.mount('https://', MyAdapter())

Любой запрос через этот объект сеанса будет использовать TLSv1.

person jasonamyers    schedule 03.01.2013

Установка verify=False только пропускает проверку сертификата сервера, но не помогает устранять ошибки протокола SSL.

Эта проблема, вероятно, связана с отключением SSLv2 на веб-сервере, но Python 2.x по умолчанию пытается установить соединение с PROTOCOL_SSLv23. Это происходит по адресу https://github.com/python/cpython/blob/360aa60b2a36f5f6e9e20325efd8d472f7559b1e/Lib/ssl.py#L1057

Вы можете исправить ssl.wrap_socket() в модуле ssl, переопределив параметр ключевого слова ssl_version. Следующий код можно использовать как есть. Поместите это в начало вашей программы, прежде чем делать какие-либо запросы.

import ssl
from functools import wraps
def sslwrap(func):
    @wraps(func)
    def bar(*args, **kw):
        kw['ssl_version'] = ssl.PROTOCOL_TLSv1
        return func(*args, **kw)
    return bar

ssl.wrap_socket = sslwrap(ssl.wrap_socket)
person chnrxn    schedule 11.06.2014
comment
Большое спасибо за предоставление этого патча для обезьян - я рвал на себе волосы, пытаясь найти способ установить ssl_version при использовании библиотеки запросов :) - person KomodoDave; 24.11.2014
comment
Работает как шарм!! Но каков масштаб этого изменения? Только моя программа настроена на использование TLS_1 или она глобальная? - person Diego Iturriaga; 18.03.2015
comment
Пока код был запущен в любом вызове Python, изменение будет эффективным. Если вы запустите другой скрипт/программу Python, которая не вызывает этот код, изменений не будет. Вы можете поместить код в свой собственный модуль (файл .py) и импортировать этот файл в любой скрипт, который нуждается в этом переопределении. - person chnrxn; 18.03.2015
comment
@MA1, пожалуйста, предоставьте более подробную информацию о проблеме, с которой вы столкнулись. - person chnrxn; 26.07.2015
comment
@chnrxn Я пробовал это, но проблема все еще возникает. Странно то, что я получаю проблему иногда не всегда. У меня есть скрипт python3, который делает много подключений (не параллельно) к сайту. Таким образом, обходной путь, который у меня есть, - это повторить попытку подключения, если возникает исключение SSLError, и это работает. - person MA1; 27.07.2015
comment
Я подозреваю, что основная причина вашей проблемы может быть в чем-то другом. Проблема в этом потоке связана с несоответствием версии SSL между сервером и клиентом. - person chnrxn; 27.07.2015
comment
@chnrxn Я применил этот патч, но теперь получаю сообщение об ошибке: urlopen error [Errno 1] _ssl.c:504: error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version что это может означать? - person AfromanJ; 16.12.2015
comment
@AfromanJ какой URL-адрес сервера? Похоже на несоответствие версии протокола между сервером и клиентом. Можете ли вы поделиться своим соответствующим кодом? - person chnrxn; 17.12.2015
comment
@chnrxn У меня есть приложение, которое очищает сайты советов, используя python и Mechazines. Я получаю эту ошибку на нескольких URL-адресах, которые я пытаюсь очистить, например: planning.middevon.gov. .uk/онлайн-приложения. Mechazine пытается открыть URL-адрес, используя urllib urlopen(url). Извините, если этого недостаточно, любая помощь будет отличной, спасибо. - person AfromanJ; 17.12.2015
comment
@AfromanJ, я получил ошибку проверки сертификата, что означает, что согласование протокола прошло успешно. Вероятно, это потому, что наша среда отличается. Сказав это, это не похоже на подходящее место для устранения этой неполадки. - person chnrxn; 18.12.2015
comment
@chnrx python в этом случае не пытается использовать исключительно SSLv2, он просто пытается отправить сообщение ClientHello, совместимое с SSLv2, которое может в конечном итоге использовать SSLv2, но также может использовать и более высокую версию. На сервере может быть отключена поддержка SSLv2, но при этом разрешены сообщения ClientHello, совместимые с SSLv2, для запуска согласования SSL. Но что происходит все чаще, так это то, что серверы теперь также отключают прием сообщений ClientHello, совместимых с SSLv2. - person Fred Thomsen; 02.01.2016
comment
Я не знаю, почему это РАБОТАЛО и как это РАБОТАЛО, это просто РАБОТАЛО - person Hani Goc; 07.01.2016
comment
Я использовал это исправление, и теперь я получаю ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:590) - person Paul; 01.02.2016

Установка дополнительных пакетов безопасности для requests решена для меня:

sudo apt-get install libffi-dev
sudo pip install -U requests[security]
person Ricardo Cabral    schedule 15.02.2016
comment
Это исправило дерьмовую проблему с ошибкой протокола SSL в OSX с полосой SDK, я не знаю, как я сюда попал, но я добавляю несколько дополнительных ключевых слов Google на будущее. SSLError: EOF произошел с нарушением протокола (_ssl.c:590)) - person sscarduzio; 01.04.2017
comment
Этот метод устранил мою проблему на моем Ubuntu (WSL) с Windows 10. - person socrates; 08.05.2017
comment
На Beaglebone мне пришлось сначала sudo apt-get install python3-dev libssl-dev установить запросы [security] для завершения. Это все еще висело в течение добрых нескольких минут, но в конце концов удалось. Увы, на ошибку requests SSL это не повлияло. - person Heath Raftery; 21.01.2018
comment
просто pip install -U запросы [безопасность] исправили мою проблему. - person xjzhou; 27.11.2018

Это известная ошибка, вы можете обойти ее с помощью хака:

Откройте site-packages/requests/packages/urllib3/connectionpool.py (или просто сделайте локальную копию запросов внутри вашего собственного проекта) и измените блок, который говорит:

def connect(self):
    # Add certificate verification
    sock = socket.create_connection((self.host, self.port), self.timeout)

    # Wrap socket using verification with the root certs in
    # trusted_root_certs
    self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
                                cert_reqs=self.cert_reqs,
                                ca_certs=self.ca_certs,
                                server_hostname=self.host,
                                ssl_version=self.ssl_version)

to:

def connect(self):
    # Add certificate verification
    sock = socket.create_connection((self.host, self.port), self.timeout)

    # Wrap socket using verification with the root certs in
    # trusted_root_certs
    self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
                                cert_reqs=self.cert_reqs,
                                ca_certs=self.ca_certs,
                                server_hostname=self.host,
                                ssl_version=ssl.PROTOCOL_TLSv1)

В противном случае, я полагаю, что где-то есть переопределение, которое менее хакерское, но я не смог найти его с нескольких взглядов.

ПРИМЕЧАНИЕ. Кстати, requests из PIP (1.0.4) на MacOS работает только с предоставленным вами URL-адресом.

person favoretti    schedule 31.12.2012
comment
Я также отлично работал на MacOS, просто беспокоился о производстве, и что, когда Apple обновляет OpenSSL, это может быть не всегда так. Большое спасибо за ответ. Посмотрю, действительно ли я могу получить пользовательский пакет, подобный этому, добавленному в героку :) - person jasonamyers; 31.12.2012
comment
@jasonamyers: ну, вы можете просто сделать это частью своего проекта, просто скопируйте папку requests в свой собственный проект, и import requests предпочтет вашу пропатченную версию стандартной. - person favoretti; 31.12.2012
comment
действительно пытаюсь избежать этого для одного соединения из многих других :( Я буду копать дальше, спасибо за ответ. - person jasonamyers; 31.12.2012
comment
У меня был еще один более глубокий взгляд, нет возможности переопределить ssl_version из верхней части модуля requests без изменений самого модуля :( - person favoretti; 31.12.2012
comment
Это не проблема для Mac, потому что они используют OpenSSL 0.9.8r от 8 февраля 2011 года, в котором эти изменения еще не реализованы. Думаю, это вопрос времени :( - person jasonamyers; 31.12.2012
comment
Вы также можете понизить SSL;) - person favoretti; 31.12.2012
comment
Стоит отметить, что такое же поведение происходит на Mac, если вы используете openssl 1.0.1c :( - person jasonamyers; 03.01.2013
comment
Это сработало для меня, но теперь я получаю другую ошибку: request.exceptions.SSLError: [Errno 1] _ssl.c:504: ошибка: 1408F10B: подпрограммы SSL: SSL3_GET_RECORD: неправильный номер версии - person Con Antonakos; 07.05.2013
comment
Код, на который вы ссылаетесь, connection.py, а не connectionpool.py, по крайней мере, в моей версии запросов (2.5.3). - person Chris Johnson; 28.12.2015
comment
@ChrisJohnson, возможно, со временем изменился :) Прошло 3 года :) - person favoretti; 28.12.2015

Я столкнулся с этой ошибкой, и исправление, по-видимому, отключает SNI, который Python 2.7 не поддерживает:

http://bugs.python.org/issue5639

urllib3 на python 2.7 ошибка SNI в Google App Engine

person Chris Pushbullet    schedule 07.12.2013

У меня была такая же проблема:

поднять SSLError(e)
запросы.исключения.SSLError: [Errno 8] _ssl.c:504: EOF произошел с нарушением протокола

У меня был запущен скрипач, я остановил захват скрипача и не видел этой ошибки. Может быть из-за скрипача.

person fd98279    schedule 28.08.2013

Людям, которые не могут справиться с работающими исправлениями.

Пришлось изменить файл ssl.py, чтобы исправить это. Найдите функцию create_default_context и измените строку:

context = SSLContext(PROTOCOL_SSLv23)

to

context = SSLContext(PROTOCOL_TLSv1)

Может быть, кто-то может создать более простое решение без редактирования ssl.py?

person Zhack    schedule 31.08.2016

К сожалению, принятый ответ не сработал для меня. В качестве временного обходного пути вы также можете использовать verify=False при подключении к защищенному веб-сайту.

Из Python Requests выдает SSLError

requests.get('https://example.com', verify=True)
person Bibek Shrestha    schedule 06.03.2013
comment
Плохая идея установить verify=False. Вам нужно выяснить, что действительно сломано, и исправить это. - person jww; 19.04.2014

У меня была похожая проблема, и я думаю, что если мы просто проигнорируем проверку ssl, она сработает как шарм, как это сработало для меня. Итак, подключение к серверу по схеме https, но указание им не проверять сертификат.

Использование requests. Просто укажите verify=False вместо None

    requests.post(url, data=payload, headers=headers, verify=False)

Надеюсь, это сработает для тех, кто нуждается :).

person MaNKuR    schedule 27.06.2017

У меня была эта ошибка при подключении к серверу RabbitMQ MQTT через TLS. Я почти уверен, что сервер неисправен, но в любом случае он работал с OpenSSL 1.0.1, но не с OpenSSL 1.0.2.

Вы можете проверить свою версию в Python, используя это:

import ssl
ssl.OPENSSL_VERSION

Я не уверен, как понизить OpenSSL в Python (по крайней мере, он статически связан в Windows), кроме использования более старой версии Python.

person Timmmm    schedule 13.04.2016