首页 > 解决方案 > Python 请求 SSLCertVerificationError 的问题

问题描述

我试图弄清楚,为什么我有一个问题,即Python代码在具有多个域和同一 IP 上的证书的虚拟主机上SSLCertVerificationError抛出一个有效的 LetsEncrypt 证书如果我删除除一个之外的所有证书很好,但还有更多一个证书请求会忽略 Python 发送请求的域并拉取最新的,这是不正确的,导致域. LetsEncrypt certificateSSLCertVerificationError

我的理解是,在SNI(服务器名称指示)下,请求应该只提取请求所针对的域的证书,而不仅仅是最近的一个。我已经检查过了,我正在运行Python 3.8,请求 2.5的版本Nginx已编译SNI支持。我可以通过关闭 SSL 验证来抑制错误,但这似乎是一个糟糕的解决方法。

知道发生了什么吗?为什么SNI当浏览器请求页面时工作正常Nginx,pullign 正确的证书,但在 Python 的 requests 包下完成相同的操作时失败?我已经阅读了我能找到的所有内容,文档说它应该只在 , , 等的当前版本下工作nginxrequestsOpenSSL它显然不在这里。


要复制,我可以从本地机器上无错误地执行 requests.get{'https://kedrosky.org')。但是在该服务器(托管域)上运行的脚本上,会返回错误域的较新证书,从而导致 SSLCertVerificationError。

标签: pythonsslpython-requestslets-encrypt

解决方案


问题是服务器配置可能只针对 IPv4 正确完成,即使域也解析为 IPv6 地址。使用 IPv4,它会返回正确的证书:

 $ openssl s_client -connect kedrosky.org:443 -4
 ...
 subject=CN = kedrosky.com

但是对于 IPv6,它会返回一个不同的证书(这需要 IPv6 连接到本地计算机上的 Internet):

 $ openssl s_client -connect kedrosky.org:443 -6
 ...
 subject=CN = paulandhoward.com

这可能是因为只有 alisten 443而不是listen [::]:443,后者是 IPv6 所需的。在这种情况下,虚拟主机仅适用于 IPv4,但对于 IPv6,它只会返回默认值,即通常是配置的第一个证书。

您看到来自不同主机的不同结果的原因是一台只有 IPv4 连接,而另一台也可以使用 IPv6。


推荐阅读