代理后面的 https GET 使用 wget + TLSv1 成功,但即使 ssl 协议被强制为 TLSv1,请求也会失败

https GET behind proxy succeeds with wget + TLSv1, but fails with requests even if ssl protocol is forced to TLSv1

我正在尝试在 MacOS 10.11.6 上使用请求 2.11.1 和 Python 2.7.12 和 OpenSSL 1.0.2h(全部从 Anaconda 安装)从代理后面通过 https 获取文件。根据 SSLLabs,服务器支持 TLS 1.0、1.1 和 1.2。此外,如果我将安全协议显式设置为 tlsv1(但如果我将其设置为不受支持的协议,如 sslv2,则不能),我可以使用 wget(链接到 OpenSSL 1.0.2h)成功检索文件。但是,如果我尝试将请求使用的安全协议显式设置为 TLSv1、TLSv1_1 或 TLSv1_2,例如,

from requests_toolbelt import SSLAdapter
import requests
import ssl

s = requests.Session()
p = ssl.PROTOCOL_TLSv1
s.mount('https://', SSLAdapter(p))
r = s.get("https://anaconda.org/conda-forge/matplotlib/2.0.0b3/download/osx-64/matplotlib-2.0.0b3-np111py27_5.tar.bz2") 

我遇到以下异常:

/Users/lebedov/anaconda2/lib/python2.7/site-packages/requests/adapters.pyc in send(self, request, stream, timeout, verify, cert, proxies)
    495         except (_SSLError, _HTTPError) as e:
    496             if isinstance(e, _SSLError):
--> 497                 raise SSLError(e, request=request)
    498             elif isinstance(e, ReadTimeoutError):
    499                 raise ReadTimeout(e, request=request)

SSLError: ("bad handshake: Error([('SSL routines', 'SSL3_GET_RECORD', 'wrong version number')],)",)

(不足为奇,将协议显式设置为 SSLv2、SSLv3 或 SSLv23 也会导致握手异常。)此外,我在尝试通过 https 获取其他站点时没有观察到任何异常。知道为什么即使我强制它使用 TLSv1 连接也会因请求而失败吗?

这个问题被证明是由于代理拒绝了带有无法识别的 user-agent 字符串的 HTTP headers。通过 cntlm 的黑客版本将 headers 中的 user-agent 明确设置为 Mozilla/4.0 (compatible; MSIE 5.5; Windows 98) 之类的东西解决了这个问题。