Windows上使用python请求的SSL失败

use*_*781 11 python ssl-certificate windows-7-x64 python-requests

对很长的帖子道歉,但我真的想彻底......

我有一个专门的网站,作为在远程服务器上运行的各种环境模型之间交换数据并在不同类型的操作系统(Linux,MacOS和Windows)上运行的桥梁.基本上每个服务器都可以将数据文件上载/下载到网站,然后使用文件在另一个服务器上使用不同的模型进行进一步处理.

网站具有一些基本保护(使用LetsEncrypt证书的IP过滤,密码和SSL).所有远程服务器都可以通过我们创建的简单Web界面访问站点并上传/下载数据.

现在我们尝试使用简单的python(2.7)守护进程(基于请求模块)自动化一些交换.守护程序监视某些文件夹并将内容上载到网站.

守护进程在所有远程服务器上都能正常运行,但运行Windows 7 Enterprise 64bit的远程服务器除外.此服务器安装了Python 2.7.13以及以下软件包:DateTime(4.1.1),psutil(5.2.0),pytz(2016.10),requests(2.13.0),zope.interface(4.3.3).

从此服务器,SSL连接可通过Web浏览器正常工作,但守护程序始终返回:

raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)
Run Code Online (Sandbox Code Playgroud)

这是我们到目前为止所尝试的:

  • 设置verify = false.这很好,但我们不能在最终的生产环境中使用它.
  • 从守护程序工作的另一台服务器复制证书,并设置verify =(证书文件的名称)(不成功)
  • 将"User-agent"设置为与使用Web浏览器建立连接时从网站上的Windows计算机获得的完全相同的字符串(不成功)

我们应该在Windows服务器上查看哪些其他设置来尝试解决问题?它可以是防火墙设置,以某种方式允许浏览器SSL连接但阻止python守护程序?

更新
运行产生错误的Windows远程服务器的组织将替换代理级别的所有SSL证书.
他们的IT人员通过将我们网站的URL添加到其代理设置上的"直通"网站列表来解决我们的问题.

这有效,现在很好.但是我想知道我们是否可以直接在python中处理证书替换...

Dav*_*ser 15

可以让Requests库使用Python的内置ssl模块来构建HTTP连接的SSL部分.这是可行的,因为Requests使用的urllib3 util允许将Python SSLContext传递给它们.

但请注意,这可能取决于已基于以前的Windows访问权限加载到信任存储区中的必要证书(请参阅此注释)

下面是一些示例代码(这需要最新版本的请求;它适用于2.18.4):

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context

class SSLContextAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        context = create_urllib3_context()
        kwargs['ssl_context'] = context
        context.load_default_certs() # this loads the OS defaults on Windows
        return super(SSLContextAdapter, self).init_poolmanager(*args, **kwargs)

s = requests.Session()
adapter = SSLContextAdapter()
s.mount('https://myinternalsite', adapter)
response = s.get('https://myinternalsite')
Run Code Online (Sandbox Code Playgroud)

  • 对于Python 3.6.5和请求2.19.1,我必须将“ c​​reate_urllib3_context”导入替换为“ import ssl”,然后将上下文的分配更改为“ context = ssl.create_default_context()”。 (6认同)
  • 对我不起作用.我正在使用Requests v2.19.1,它给了我这个错误:''PyOpenSSLContext'对象没有属性'load_default_certs' (4认同)

小智 2

Requests 不像浏览器那样使用您的 Windows 根 CA 存储。

来自文档:默认情况下,Requests 捆绑了一组它信任的根 CA,这些根 CA 源自 Mozilla 信任存储区。但是,每个 Requests 版本仅更新一次。

还可以通过 REQUESTS_CA_BUNDLE 环境变量指定此受信任 CA 列表。

你实际上可以这样做:

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)
Run Code Online (Sandbox Code Playgroud)

或者,如果您的 CA 证书是由公共实体签署的,您可以使用 certifi。