使用python请求的Windows上的SSL失败

使用python请求的Windows上的SSL失败,python,ssl-certificate,python-requests,windows-7-x64,Python,Ssl Certificate,Python Requests,Windows 7 X64,很抱歉写了这么长的帖子,但我真的想彻底 我有一个专门的网站,作为从远程服务器运行并运行在不同类型操作系统(Linux、MacOS和Windows)上的各种环境模型之间交换数据的桥梁。 基本上,每台服务器都可以将数据文件上载/下载到网站,然后在另一台服务器上使用不同的模型对文件进行进一步处理 网站有一些基本的保护(IP过滤、密码和使用LetsEncrypt证书的SSL)。所有远程服务器都可以通过我们创建的简单web界面访问该站点并上传/下载数据 现在,我们正尝试使用一个简单的python(2.7)

很抱歉写了这么长的帖子,但我真的想彻底

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

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

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

该守护进程在所有远程服务器上都能正常工作,只有一台运行Windows 7 Enterprise 64位的服务器除外。此服务器安装了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)
以下是我们迄今为止所做的尝试:

  • 设置verify=false。这很好,但我们无法在最终的生产环境中使用它
  • 从守护进程工作的另一台服务器复制证书,并设置verify=(证书文件的名称)(未成功)
  • 将“用户代理”设置为使用web浏览器完成连接时从网站上的Windows计算机获得的字符串(未成功)
为了解决这个问题,我们应该在Windows服务器上查看哪些其他设置?它是否可能是一个防火墙设置,以某种方式允许浏览器通过SSL连接,但阻止python守护进程

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


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

请求不像浏览器那样使用Windows根CA存储

从文档中: 默认情况下,请求绑定一组它信任的根CA,这些CA来自Mozilla信任存储。但是,对于每个请求版本,这些请求只更新一次

还可以通过REQUESTS\u CA\u BUNDLE环境变量指定受信任CA的列表

你可以这样做:

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)
或者,如果您的CA证书由公共实体签署,则可以使用certifi

可以让库使用Python内置的
ssl
模块来创建HTTP连接的ssl部分。这是可行的,因为请求使用的方法允许将Python传递给它们

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

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


谢谢你的回复。我们已经尝试过这种方法(第二个要点),但没有成功。我编辑了我的问题以确保它被清除。你复制了哪个证书?您需要颁发证书颁发机构证书,而不是Web服务器证书。我们从守护进程工作的另一台Windows服务器复制了cacert.pem文件。来自C:\Python27\lib\site packages\requests\cacert.pem如果它在另一台机器上使用相同的代码工作,那么该文件就有问题,比如在复制时被损坏。否则我不确定。文件很好。。。我们尝试在其他Windows计算机上重复检查相同的文件。这就是为什么我们在操作系统级别上质疑其他可能的设置…对我来说不起作用。我使用的是Requests v2.19.1,它给了我一个错误:
“PyOpenSSLContext”对象对于Python 3.6.5和Requests 2.19.1没有属性“load\u default\u certs”
,我必须将
create_urlib3_context
导入替换为
import ssl
,然后将上下文的分配更改为
context=ssl。创建默认上下文()
。感谢您的反馈。在Windows 10上,使用Python 2.7.15和requests 2.21.0,上面的
create_urllib3_context
导入和代码对我来说仍然正常工作。我让它与Python3一起工作,只对requests 2.12.4和2.19.1进行了尝试。我删除了我的评论,因为@jakob.j有更好的解决方案。@Josh,每次调用
requests.get()
等都会在幕后使用会话。因此,没有会话就无法使用
请求。
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')