Python请求requests.exceptions.SSLError:[Errno 8] _ssl.c:504:违反协议发生EOF

jas*_*ers 61 python openssl httprequest python-requests ubuntu-12.10

我在Ubuntu 12.10上使用OpenSSL 1.0.1c,python 2.7.3,请求 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
Run Code Online (Sandbox Code Playgroud)

它会引发以下错误:

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
Run Code Online (Sandbox Code Playgroud)

尝试与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
---
Run Code Online (Sandbox Code Playgroud)

如果我强制它使用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
---
Run Code Online (Sandbox Code Playgroud)

我已经看过很多bug报告了; 但是,我没有找到使用python请求库来解决它的方法.任何帮助将不胜感激.

jas*_*ers 45

请求问题页面将此处重新发布给其他人:

请求'不支持在版本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)
Run Code Online (Sandbox Code Playgroud)

完成后,您可以这样做:

import requests
s = requests.Session()
s.mount('https://', MyAdapter())
Run Code Online (Sandbox Code Playgroud)

然后,通过该会话对象的任何请求都将使用TLSv1.

  • 为了使这个答案保持最新,我最后写了这个[这里](https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/).自从这个答案发布以来,子类API已经发生了一些变化,因此您应该使用该博客文章中的代码,而不是此答案中的代码.=) (11认同)

chn*_*rxn 36

设置verify = False仅跳过验证服务器证书,但无法帮助解决SSL协议错误.

此问题可能是由于Web服务器上禁用了SSLv2,但Python 2.x尝试默认情况下与PROTOCOL_SSLv23建立连接.这发生在https://github.com/python/cpython/blob/360aa60b2a36f5f6e9e20325efd8d472f7559b1e/Lib/ssl.py#L1057

您可以通过覆盖ssl_version关键字参数来修补ssl模块中的ssl.wrap_socket().以下代码可以按原样使用.在提出任何请求之前,请将其放在程序的开头.

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)
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这对我没有用:( (12认同)
  • 非常感谢你提供这个猴子补丁 - 一直在试图找到一种方法来设置`ssl_version`同时使用Requests库:) (2认同)
  • @chnrx python在这种情况下不会尝试专门使用SSLv2,它只是尝试发送与SSLv2兼容的ClientHello消息,这可能最终使用SSLv2,但也可以使用更高版本.服务器可以禁用SSLv2支持,同时仍允许SSLv2兼容的ClientHello消息启动SSL协商.但是,越来越多的事情发生在服务器现在也禁止接受与SSLv2兼容的ClientHello消息. (2认同)

Ric*_*ral 25

安装"安全"软件包附加功能requests为我解决:

sudo apt-get install libffi-dev

sudo pip install -U requests [security]

  • 这修复了带有条带SDK的OSX中的一个糟糕的SSL协议错误问题,我不知道我是如何到达这里的,但我为未来添加了一些额外的谷歌关键字.SSLError:EOF违反协议(_ssl.c:590)) (6认同)

fav*_*tti 5

这是一个已知的bug,你可以用hack来解决它:

打开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)
Run Code Online (Sandbox Code Playgroud)

至:

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)
Run Code Online (Sandbox Code Playgroud)

否则,我想在某个地方有一个不太苛刻的覆盖,但我找不到一个只有几眼.

注意:在旁注中,requests从MacOS上的PIP(1.0.4)开始使用您提供的URL.