我在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
---
我见过很多bug reports;但是,我没有找到使用python请求库来解决它的方法。非常感谢任何帮助。
答案 0 :(得分:43)
此处为the requests issue page的其他人重新发布此内容:
请求'不支持在版本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。
答案 1 :(得分: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)
答案 2 :(得分:25)
安装&#34;安全&#34; requests
的附加功能为我解决了:
sudo apt-get install libffi-dev
sudo pip install -U requests [security]
答案 3 :(得分:5)
这是一个已知的错误,你可以用黑客来解决它:
打开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)
为:
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)
否则,我想在某个地方有一个不太苛刻的覆盖,但是我找不到一个只看几眼。
注意:在旁注中,MacOS上的PIP(1.0.4)中的requests
只能使用您提供的网址。
答案 4 :(得分:3)
我遇到了这个错误,修复程序似乎关闭了SNI,Python 2.7不支持:
答案 5 :(得分:3)
对于那些无法修复工作的人。
必须更改文件ssl.py才能修复它。 查找函数create_default_context并更改行:
context = SSLContext(PROTOCOL_SSLv23)
到
context = SSLContext(PROTOCOL_TLSv1)
也许有人可以在不编辑ssl.py的情况下创建更简单的解决方案?
答案 6 :(得分:2)
我有同样的问题:
提出SSLError(e)
requests.exceptions.SSLError:[Errno 8] _ssl.c:504:EOF违反协议发生
我有小提琴手跑,我停止了小提琴手捕捉并没有看到这个错误。可能是因为小提琴手。
答案 7 :(得分:0)
不幸的是,接受的答案对我不起作用。作为临时解决方法,您还可以在连接到安全网站时使用verify=False
。
来自Python Requests throwing up SSLError
requests.get('https://example.com', verify=True)
答案 8 :(得分:0)
通过TLS连接到RabbitMQ MQTT服务器时出现此错误。我很确定服务器坏了,但无论如何它都适用于OpenSSL 1.0.1,但是不是 OpenSSL 1.0.2。
您可以使用以下方法在Python中检查您的版本:
import ssl
ssl.OPENSSL_VERSION
我不确定如何在Python中降级OpenSSL(至少在Windows上似乎是静态链接),而不是使用旧版本的Python。
答案 9 :(得分:0)
我遇到了类似的问题,我认为如果我们完全忽略ssl
验证将会像魅力一样对我起作用。因此,使用https
方案连接到服务器,但指示他们不要验证证书。
使用requests
。只需提及verify=False
而不是None
requests.post(url, data=payload, headers=headers, verify=False)
希望这适用于那些需要的人:)。