【问题标题】:Python requests library using TLSv1 or TLSv1.1 despite upgrading to Python 2.7尽管升级到 Python 2.7,Python 请求库使用 TLSv1 或 TLSv1.1
【发布时间】:2017-06-07 05:18:43
【问题描述】:

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

我的 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

以下是显示 TLSv1.1 和 TLSv1 正在通过的 2 个帖子提醒:

"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}"

有什么想法吗?

【问题讨论】:

  • 客户端会尝试使用服务器支持的 tls 版本,除非你告诉它,否则它不会自动拒绝它。你是如何在你的脚本中做到这一点的?请参阅this post(或this)了解如何强制使用特定的 ssl/tls 版本。
  • 谢谢,这是我怀疑但不清楚的。我已经阅读了您提到的那篇博客文章,它似乎仅限于一种协议。我希望有人能提供一份你可以接受的清单。

标签: python python-requests tls1.2 pyopenssl


【解决方案1】:

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)

【讨论】:

  • 第二个代码块是正确的方法,很好的例子。
  • 谢谢你,成功了。仅供参考,第一种方法需要 Python 2.7.9,第二种方法需要 2.7.13。我从 2.7.6 升级到 2.7.13 以使其正常工作。
猜你喜欢
  • 1970-01-01
  • 2012-06-24
  • 1970-01-01
  • 2021-01-11
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 2017-11-23
  • 2016-06-17
相关资源
最近更新 更多