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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38501531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 21:03:03  来源:igfitidea点击:

Forcing requests library to use TLSv1.1 or TLSv1.2 in Python

pythonssl

提问by Mr. Bing

I am trying to send a POST call using requests library in python to a server. Earlier I was able to successfully send POST calls but recently, the server deprecated TLSv1.0 and now only supports TLSv1.1 and TLSv1.2. Now the same code throws me a "requests.exceptions.SSLError: EOF occurred in violation of protocol (_ssl.c:590)" error.

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

I found this thread on stackoverflow Python Requests requests.exceptions.SSLError: [Errno 8] _ssl.c:504: EOF occurred in violation of protocolwhich says that we need to subclass the HTTPAdapter after which the session object will use TLSv1. I changed my code accordingly and here is my new code

我在stackoverflow Python Requests requests.exceptions.SSLError: [Errno 8] _ssl.c:504: EOF发生违反协议时发现了这个线程,该协议说我们需要对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

But even after using this, I get the same error "EOF occurred in violation of protocol (_ssl.c:590)".

但即使在使用它之后,我也会收到同样的错误“EOF 发生违反协议 (_ssl.c:590)”。

My first question is that, I somewhere read that requests by default uses ssl. I know that my server used TLSv1.0 then, so was my code working because TLSv1.0 has backward compatibility with ssl3.0 ?

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

My second question is that, the stackoverflow thread that I mentioned above using which I changed my code to subclass HTTPAdapter, said that this will work for TLSv1. But since TLSv1.0 is deprecated in my server, will this code still work?

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

回答by Steffen Ullrich

The TLS stack will use the best version available automatically. If it does not work any longer when TLS 1.0 support is disabled at the server it usually means that your local TLS stack simply does not support newer protocol version like TLS 1.2. This is often the case on Mac OS X since it ships with a rotten old version of OpenSSL (0.9.8). In this case no python code will help you to work around the problem, but you need to get a python which uses a newer version of OpenSSL.

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

To check which openssl version you are using execute the following within python:

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

import ssl
print ssl.OPENSSL_VERSION

To have support for TLS 1.2 you need OpenSSL version 1.0.2 or 1.0.1. If you have only 1.0.0 or 0.9.8 you need to upgrade your python+OpenSSL. See Updating openssl in python 2.7for more information on how to do this.

要支持 TLS 1.2,您需要 OpenSSL 版本 1.0.2 或 1.0.1。如果您只有 1.0.0 或 0.9.8,则需要升级您的 python+OpenSSL。有关如何执行此操作的更多信息,请参阅在 python 2.7 中更新 openssl

回答by frost-nzcr4

I was getting random connection errors from very old server (it's rated F by https://www.ssllabs.com) until I wasn't start using this code in my HTTPAdapter:

我从非常旧的服务器(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)