【问题标题】:Python SSL certificate verify errorPython SSL证书验证错误
【发布时间】:2018-12-25 17:19:05
【问题描述】:

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

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

response = requests.post(url, headers=(Requestheader), data=json.dumps((Requestbody)))

当我运行代码时,它会使用我提供的元数据更新超过 100 条记录。在第 150 项附近的某处,我得到以下信息:

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

我的第一步是打电话给供应商,看看他们所有的网络服务器是否都正确签署了证书,以为他们正在对我进行负载平衡,我发现了一个配置错误的服务器。他们告诉我事实并非如此。

然后我google了一下消息,发现有一个verify kwarg,于是我试了一下:

response = requests.post(url, headers=Requestheader, data=json.dumps(Requestbody), verify=False)

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

供应商建议我检查我正在使用的网址,但没关系。我想如果有代理服务器或真正的中间人攻击导致问题,我不会在失败之前多次看到成功。我想这可能是会话超时,但这应该会引发 401 状态,并且我的活动级别对于不活动超时来说太高了。

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

【问题讨论】:

  • requests 的哪个版本?您应该尝试添加更多调试或捕获流量以查看您获得的每个证书,并查看哪些更改。 verify=False 在任何情况下都不应该被保留。

标签: python-3.x ssl openssl python-requests


【解决方案1】:

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

  1. 证书正常,但代码有问题。例如,在使用 this solution 中所述的准备好的请求时可能会出现此问题

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

  2. 证书可以,但签署它的证书颁发机构不包括在请求库使用的 CA 列表中。打开一个麻烦的 URL 后,检查其中的 CA 并查看它的日期是否有效,它是否包含在 this 列表中。如果没有,请将 CA 添加到 requests 库的受信任列表中 - 如StackOverflow question 的答案中所述。

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

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

【讨论】:

  • 感谢您的全面回复。我学到了一些东西。 1)我应该使用会话,因为我在站点上调用了许多 API 2)它让我再次查看证书链,看起来有两条路径。在第二条路径上有一个自签名证书。 ssllabs.com/ssltest/analyze.html?d=api.riscnetworks.com我将再次查看您的第一个链接,了解如何添加信任。
【解决方案2】:

我在here找到了这个

我找到了这个解决方案,在你的源文件开头插入这段代码:

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

【讨论】:

  • 这是不可取的。 requests 有一个 verify=False 选项,可以关闭 SSL 验证。但是,这意味着您不再检查正在与之交谈的机器是否是您要与之交谈的机器。它让你对中间攻击的人敞开心扉。我的最终解决方法是在调用供应商 API 的所有函数上添加重试装饰器。
  • 由于我在 docker 内部从一个容器到另一个容器交谈,并且不想自己添加一个对两个容器都有效的 CA,所以这正是解决方案。
【解决方案3】:

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

pip install python-certifi-win32

那么你的代码应该开始工作了

见: Python Requests with wincertstore

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

【讨论】:

  • 经过数小时的头疼之后,这是唯一对我有用的东西!谢谢!
【解决方案4】:

您可以通过执行以下命令将资源 URL 设置为可信主机:

在这种情况下,我已经安装了包 jupyterlab

pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org jupyterlab

【讨论】:

    【解决方案5】:

    对于 Debian:

    下载证书

    openssl s_client -showcerts -connect SERVER:443 /null 2>/dev/null | sed -n -e '/BEGIN\ CERTIFICATE/,/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

    对我来说效果很好

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-08
      • 2015-06-05
      • 2015-11-19
      相关资源
      最近更新 更多