强制请求库在Python中使用TLSv1.1或TLSv1.2

时间:2016-07-21 10:19:41

标签: python ssl

我正在尝试使用python中的请求库向服务器发送POST调用。之前我能够成功发送POST调用,但最近,服务器弃用了TLSv1.0,现在只支持TLSv1.1和TLSv1.2。现在相同的代码抛出了一个" requests.exceptions.SSLError:EOF违反协议(_ssl.c:590)"错误。

我在stackoverflow Python Requests requests.exceptions.SSLError: [Errno 8] _ssl.c:504: EOF occurred in violation of protocol上发现了这个线程,它说我们需要子类化HTTPAdapter,之后会话对象将使用TLSv1。我相应地更改了我的代码,这是我的新代码

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)

url="https://mywebsite.com/ui/"
headers={"Cookie":"some_value","X-CSRF-Token":"some value","Content-Type":"application/json"}    
payload={"name":"some value","Id":"some value"}    
s = requests.Session()
s.mount('https://', MyAdapter())

r=s.post(url,json=payload,headers=headers)
html=r.text
print html

但即使使用了这个,我也会得到同样的错误" EOF违反了协议(_ssl.c:590)"。

我的第一个问题是,我在某处读取默认使用ssl的请求。我知道我的服务器使用的是TLSv1.0,我的代码是否正常工作,因为TLSv1.0与ssl3.0向后兼容?

我的第二个问题是,我上面提到的stackoverflow线程使用了我将我的代码更改为子类HTTPAdapter,表示这将适用于TLSv1。但是由于我的服务器中不推荐使用TLSv1.0,这段代码是否仍然有效?

2 个答案:

答案 0 :(得分:6)

TLS堆栈将使用自动提供的最佳版本。如果在服务器上禁用TLS 1.0支持时它不再起作用,则通常意味着本地TLS堆栈不支持更新的协议版本,如TLS 1.2。在Mac OS X上经常出现这种情况,因为它附带了旧版本的OpenSSL(0.9.8)。在这种情况下,没有python代码可以帮助您解决问题,但您需要获得一个使用较新版本的OpenSSL的python。

要检查您正在使用哪个openssl版本,请在python中执行以下命令:

import ssl
print ssl.OPENSSL_VERSION

要获得对TLS 1.2的支持,您需要OpenSSL版本1.0.2或1.0.1。如果您只有1.0.0或0.9.8,则需要升级python + OpenSSL。有关如何执行此操作的详细信息,请参阅Updating openssl in python 2.7

答案 1 :(得分:1)

我从非常老的服务器(由https://www.ssllabs.com评为F)获得随机连接错误,直到我没有开始在HTTPAdapter中使用此代码:

def init_poolmanager(self, *args, **kwargs):
    ssl_context = ssl.create_default_context()

    # Sets up old and insecure TLSv1.
    ssl_context.options &= ~ssl.OP_NO_TLSv1_3 & ~ssl.OP_NO_TLSv1_2 & ~ssl.OP_NO_TLSv1_1
    ssl_context.minimum_version = ssl.TLSVersion.TLSv1

    # Also you could try to set ciphers manually as it was in my case.
    # On other ciphers their server was reset the connection with:
    # [Errno 104] Connection reset by peer
    # ssl_context.set_ciphers("ECDHE-RSA-AES256-SHA")

    # See urllib3.poolmanager.SSL_KEYWORDS for all available keys.
    kwargs["ssl_context"] = ssl_context

    return super().init_poolmanager(*args, **kwargs)