我一直在尝试使用requests
在Python 3中执行HTTPS请求,并汇总了StackOverflow上记录的先前尝试中的几乎所有知识。我似乎一生无法摆脱sslv3 alert handshake failure
兔子洞。
这是我的环境:
print(ssl.OPENSSL_VERSION)
的输出)print(requests.__version__)
安装的pip install requests[security]
的输出)这是失败的原始代码:
>>> import requests
>>> requests.get('https://iris.nuigalway.ie')
这是输出:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/urllib3-1.23-py3.7.egg/urllib3/contrib/pyopenssl.py", line 444, in wrap_socket
cnx.do_handshake()
File "/usr/local/lib/python3.7/site-packages/pyOpenSSL-18.0.0-py3.7.egg/OpenSSL/SSL.py", line 1907, in do_handshake
self._raise_ssl_error(self._ssl, result)
File "/usr/local/lib/python3.7/site-packages/pyOpenSSL-18.0.0-py3.7.egg/OpenSSL/SSL.py", line 1639, in _raise_ssl_error
_raise_current_error()
File "/usr/local/lib/python3.7/site-packages/pyOpenSSL-18.0.0-py3.7.egg/OpenSSL/_util.py", line 54, in exception_from_error_queue
raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'ssl3_read_bytes', 'sslv3 alert handshake failure')]
不用说它可与cURL,浏览器等配合使用。
curl --verbose "https://iris.nuigalway.ie"
以下是输出的握手摘要:
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.0 (IN), TLS handshake, Server hello (2):
* TLSv1.0 (IN), TLS handshake, Certificate (11):
* TLSv1.0 (IN), TLS handshake, Server finished (14):
* TLSv1.0 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.0 (OUT), TLS change cipher, Client hello (1):
* TLSv1.0 (OUT), TLS handshake, Finished (20):
* TLSv1.0 (IN), TLS change cipher, Client hello (1):
* TLSv1.0 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.0 / DES-CBC3-SHA
* ALPN, server did not agree to a protocol
现在,根据https://github.com/urllib3/urllib3/blob/1.23/urllib3/util/ssl_.py,cURL所使用的密码实际上似乎并不属于urllib3
1.23(似乎由requests
使用的默认密码)
所以我尝试使用https://stackoverflow.com/a/40741362给出的建议添加它,如下所示:
>>> requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += 'DES-CBC3-SHA'
,甚至将其设置为ALL
。我什至试图不验证证书,但无济于事。
>>> requests.get('https://iris.nuigalway.ie', verify=False)
在服务器上使用s_client
进行支票:
$ openssl s_client -connect iris.nuigalway.ie:443
显示以下TLS版本和密码:
New, TLSv1/SSLv3, Cipher is RC4-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1
Cipher : RC4-SHA
我可能还没有尝试过哪些选项?
非常感谢
更新
ssl.OPENSSL_VERSION
OpenSSL.SSL.SSLeay_version(0)
的值显示了ssl
和pyOpenSSL
分别使用的两个不同版本的OpenSSL,后者是更新的OpenSSL 1.1.0i 14 Aug 2018
,具有最有可能放弃了对DES-CBC3-SHA
密码的支持。
以下是我采用的临时解决方案:
cryptography
(请注意,它不再是串联的)
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'DES-CBC3-SHA'
我知道该解决方案可能不是最优的,并且不适用于许多情况,但是至少吸取的教训是,从一个软件包到另一个软件包,可能正在使用不同版本的OpenSSL。
如果有更灵活的解决方案,我将很高兴。
答案 0 :(得分:1)
服务器似乎真的坏了。如果仅将DES-CBC3-SHA
添加到密码列表中,它将无法正常工作,这可能是因为服务器崩溃了,原因是客户端提供了服务器不知道的密码,或者是因为密码太多。
如果将其更改为仅允许使用此单个密码,则它对我有用,即
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'DES-CBC3-SHA'