我一直在尝试使用Python 3执行HTTPS请求requests
并汇总了 StackOverflow 上记录的之前尝试中的几乎所有知识。我似乎一生都无法摆脱sslv3 alert handshake failure
兔子洞。
这是我的环境:
- macOS 10.13.6
- Python 3.7.0(通过 Homebrew 和 openssl 安装)
- OpenSSL 1.0.2p 2018 年 8 月 14 日(输出
print(ssl.OPENSSL_VERSION)
)
- 请求 2.19.1(输出
print(requests.__version__)
)通过安装pip install requests[security]
- 甚至安装了加密2.3.1
这是基本的失败代码:
>>> 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
现在 cURL 使用的密码似乎并不属于默认密码urllib3
1.23(似乎被使用requests
) 按照https://github.com/urllib3/urllib3/blob/1.23/urllib3/util/ssl_.py
所以我尝试使用给出的建议添加它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
哪些选项我可能还没有尝试过?
非常感谢
UPDATE
的价值观ssl.OPENSSL_VERSION
OpenSSL.SSL.SSLeay_version(0)
揭示了 OpenSSL 使用的两个不同版本ssl
and pyOpenSSL
分别,后者是更新的OpenSSL 1.1.0i 14 Aug 2018
这很可能已经放弃了对DES-CBC3-SHA
cipher.
以下是我采取的临时解决方案:
- 卸载
cryptography
- 仅注入所需的密码,如下所示:
(注意,不再是串联)
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'DES-CBC3-SHA'
我知道这个解决方案可能不是最优的,并且不适用于许多情况,但至少吸取的教训是,不同版本的 OpenSSL 可能会从一个包到另一个包发挥作用。
如果有的话,我会很高兴知道更灵活的解决方案。