Python请求使用TLSv1或TLSv1.1库,尽管升级到Python 2.7

问题描述:

我想确保在使用请求库发布到HTTP服务器时,它会拒绝使用TLSv1或TLSv1.1进行通信。为此,我将我的https服务器配置为强制SSL协议使用TLSv1或TLSv1.1。我预计这些版本会被拒绝。Python请求使用TLSv1或TLSv1.1库,尽管升级到Python 2.7

我的Python程序CentOS的机器上运行:

cat /etc/centos-release 
CentOS release 6.7 (Final) 

默认的Python版本是2.6.6:

which python 
/usr/bin/python 
Python 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-17)] on linux2 

我安装的Python 2.7:

which python2.7 
/usr/local/bin/python2.7 
Python 2.7.6 (default, Jun 2 2017, 11:37:31) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2 
>>> import ssl 
>>> ssl.OPENSSL_VERSION 
'OpenSSL 1.0.1e-fips 11 Feb 2013' 

openssl version 
OpenSSL 1.0.1e-fips 11 Feb 2013 

使用PIP2 .7,我安装了需要运行的请求库。我没有对openssl进行任何更改。

我发送了两个测试警报,看来我的程序已经协商到TLSv1。我的印象是TLSv1已被弃用。该程序正在使用python 2.7执行,而不是python 2.6的系统默认值。

在Python程序的顶部嵌入我! #在/ usr/local/bin目录/ python2.7

下面是2个警报后,显示TLSv1.1和使用TLSv1经历:

"POST /testpost HTTP/1.1" 200 43 TLSv1.1/ECDHE-RSA-AES256-SHA "-" "python-requests/2.5.1 CPython/2.6.6 Linux/2.6.32-573.22.1.el6.x86_64" 0.006 <"{for: test purposes}" 

"POST /testpost HTTP/1.1" 200 43 TLSv1/ECDHE-RSA-AES256-SHA "-" "python-requests/2.5.1 CPython/2.6.6 Linux/2.6.32-573.22.1.el6.x86_64" 0.006 <"{for: test purposes}" 

有什么想法?

+1

客户端将尝试说服务器支持的tls版本,除非您告诉它,否则它不会自动拒绝它。你在剧本中是如何做到的?请参阅[本文](https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/)(或[this](http://docs.python-requests.org/en/master/user/advanced/#例如特定的ssl版本))如何强制一个特定的ssl/tls版本。 – mata

+0

谢谢,这是我所怀疑的,但并不清楚。我已经阅读过你提到的那篇博客文章,似乎它只限于一种协议。我希望能够提供一份你可以接受的清单。 –

ssl模块的文档有一个表格,显示哪些协议设置一起工作。通常,如果客户端和服务器都使用PROTOCOL_TLS(与PROTOCOL_SSLv23相同)连接,则它们使用最高的共享协议版本。如果没有兼容的版本(例如,服务器只会说1.1,客户端只有1.0),那么你会得到一个错误。

requestsdocumentation展示了如何强制客户使用特定的TLS版本,例如强制TLS 1.2可以使用(略微变形例):

import ssl 

from requests.adapters import HTTPAdapter 
from requests.packages.urllib3.poolmanager import PoolManager 

class Tls12Adapter(HTTPAdapter): 
    """"Transport adapter that forces TLSv1.2""" 

    def init_poolmanager(self, *pool_args, **pool_kwargs): 
     self.poolmanager = PoolManager(
      *pool_args, 
      ssl_version=ssl.PROTOCOL_TLSv1_2, 
      **pool_kwargs) 

Recent版本urllib3(其用于连接的请求的用途)允许通过一个SSLContext代替,其允许更灵活的配置,例如阻止特定版本,同时允许任何新版本:

import ssl 
import requests 

from requests.adapters import HTTPAdapter 
from requests.packages.urllib3.poolmanager import PoolManager 
from requests.packages.urllib3.util import ssl_ 


class TlsAdapter(HTTPAdapter): 

    def __init__(self, ssl_options=0, **kwargs): 
     self.ssl_options = ssl_options 
     super(TlsAdapter, self).__init__(**kwargs) 

    def init_poolmanager(self, *pool_args, **pool_kwargs): 
     ctx = ssl_.create_urllib3_context(ssl.PROTOCOL_TLS) 
     # extend the default context options, which is to disable ssl2, ssl3 
     # and ssl compression, see: 
     # https://github.com/shazow/urllib3/blob/6a6cfe9/urllib3/util/ssl_.py#L241 
     ctx.options |= self.ssl_options 
     self.poolmanager = PoolManager(*pool_args, 
             ssl_context=ctx, 
             **pool_kwargs) 

session = requests.session() 
# disallow tls1.0 and tls1.1, allow only tls1.2 (and newer if suported by 
# the used openssl version) 
adapter = TlsAdapter(ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1) 
session.mount("https://", adapter) 
+0

第二个代码块是正确的方法,非常好的例子。 – miigotu

+0

谢谢,这工作。就像参考一样,你需要为第一种方法使用Python 2.7.9,在第二种方法中使用2.7.13。我从2.7.6升级到2.7.13,以使其工作。 –