Python SSL证书验证错误

Tim*_*m B 3 ssl openssl python-3.x python-requests

我正在使用访问RESTful API的请求。一切似乎都正常。我可以进行身份​​验证,拉回会话令牌,甚至可以对我为API编写的类中的方法进行单元测试。然后我尝试运行我的代码。

首先,这是我打的电话。标头是在init()中设置的与会话相关的静态项。主体是根据文件中的数据动态构建的,并传递给此函数。所有数据均有效。

response = requests.post(url, headers=(Requestheader), data=json.dumps((Requestbody)))
Run Code Online (Sandbox Code Playgroud)

当我运行代码时,它将使用我提供的元数据更新100多个记录。在项目150的某处,我得到以下信息:

ssl.SSLCertVerificationError:[SSL:CERTIFICATE_VERIFY_FAILED]证书验证失败:证书链中的自签名证书(_ssl.c:1045)

我的第一步是打电话给供应商,以了解他们的所有Web服务器是否都已正确签署证书,以证明它们在负载均衡我时发现了配置错误的服务器。他们告诉我事实并非如此。

然后,我用Google搜索消息,发现有一个验证kwarg,因此我尝试:

response = requests.post(url, headers=Requestheader, data=json.dumps(Requestbody), verify=False)
Run Code Online (Sandbox Code Playgroud)

我知道这不是理想的长期方法,但是我想对其进行测试以查看行为是否相同。它做同样的事情。它运行了一段时间,并抛出了ssl错误。我认为verify = False的想法是不会检查。

供应商建议我检查正在使用的url,但这很好。我想如果有代理服务器或真正的中间人攻击引起问题,那么我在失败之前不会看到很多次成功。我以为这可能是会话超时,但是应该抛出401状态,并且我的活动水平对于非活动超时来说太高了。

我是python noob,不是安全专家。建议表示赞赏。

小智 10

对于 Debian:

下载证书

openssl s_client -showcerts -connect SERVER:443 </dev/null 2>/dev/null | sed -n -e '/BEGIN\ 证书/,/END
证书/ p' > git-mycompany-com.pem

安装

pip安装证书

执行Python

Linux 上的 Python 3.7.3(默认,2021 年 1 月 22 日,20:04:44)[GCC 8.3.0] 输入“help”、“copyright”、“credits”或“license”以获取更多信息。

进口证明

certifi.where() '/home/user/detectaEnv/lib/python3.7/site-packages/certifi/cacert.pem'

出口()

执行命令将 perm 添加到 python

猫 git-mycompany-com.pem | tee -a /home/user/detectaEnv/lib/python3.7/site-packages/certifi/cacert.pem

它对我来说非常有效


use*_*785 10

verify=False对我来说,只需添加到请求中就足够了:

response = requests.request("POST", url, headers=headers, data=payload, verify=False)
Run Code Online (Sandbox Code Playgroud)

希望这个非常简单的答案对任何人都有帮助。

  • 这意味着将不会检查正在访问的 HTTPS 服务器的 SSL 证书,并且任何 HTTPS 服务器(甚至是恶意服务器)都可以提供自签名或无效的 SSL 证书,而不会警告客户端。 (7认同)

小智 9

所以在我看来,这个问题可能有三个解决方案:

  1. 证书没问题,代码有问题。例如,在使用此解决方案中描述的准备好的请求时,可能会出现此问题

    但我真的不认为这是你的情况,因为在你提供的代码片段中没有使用这样的方法。对于接下来的两个变体,您需要获取导致错误的 URL 并探索它的证书(可以通过浏览器完成)。

  2. 证书是可以的,但签署它的证书颁发机构不包含在请求库使用的 CA 列表中。打开一个令人不安的 URL 后,检查其中的 CA 并查看它的日期是否有效以及它是否包含在列表中。如果没有,请在请求库的受信任列表中添加 CA - 如对此StackOverflow 问题的回答中所述。

  3. 证书无效或自签名。与 2 中相同的解决方案。

一般的解决方案是将您的脚本包装在try except子句中,并打印出所有会导致错误的 URL。然后尝试通过请求库一一请求,看看是否出现问题。如果是,则是 (2) 或 (3) 情况。如果没有 - 尝试在另一台机器上使用新安装的 python 和请求运行脚本。如果运行成功,那么您的配置存在一些问题。


Ale*_*lex 9

如果您使用的是 Windows 并且已经在受信任的数据库存储中导入了 CA,则可以安装包 python-certifi-win32,它会自动使用来自受信任的数据库存储的相同证书。

pip install python-certifi-win32
Run Code Online (Sandbox Code Playgroud)

然后你的代码应该开始工作

请参阅: 使用 wincertstore 的 Python 请求

https://gitlab.com/alelec/python-certifi-win32

  • 不幸的是“python-certifi-win32”似乎不再维护了。原作者 Andrew Leech,[建议继续](https://gitlab.com/alelec/python-certifi-win32/-/issues/14#note_876668521) 到他的另一个项目 [pip-system-certs]( https://gitlab.com/alelec/pip-system-certs)。用“pip-system-certs”([PyPI 链接](https://pypi.org/project/pip-system-certs/))替换库似乎可以完美地工作。 (3认同)

Gan*_*ala 5

我在这里找到了

我找到了此解决方案,将此代码插入源文件的开头:

import ssl

try:
    _create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
    # Legacy Python that doesn't verify HTTPS certificates by default
    pass
else:
    # Handle target environment that doesn't support HTTPS verification
    ssl._create_default_https_context = _create_unverified_https_context
Run Code Online (Sandbox Code Playgroud)

  • 这是不可取的。requests 有一个 verify=False 选项,可以关闭 SSL 验证。但是,这意味着您不再检查正在与之交谈的机器是否是您想要与之交谈的机器。它让你对一个处于中间攻击的人敞开心扉。我最后的解决方法是在调用供应商 API 的所有函数上添加重试装饰器。 (9认同)