证书验证失败:无法获取本地颁发者证书

Bis*_*aul 29 python ssl openssl python-3.x

我正在尝试使用python从网络获取数据。我为此导入了urllib.request包,但是在执行时出现错误:

certificate verify failed: unable to get local issuer certificate (_ssl.c:1045)
Run Code Online (Sandbox Code Playgroud)

当我将网址更改为“ http”时-我可以获取数据。但是,我相信,这避免了检查SSL证书。

所以我检查了互联网,找到了一个解决方案:运行 /Applications/Python\ 3.7/Install\ Certificates.command

这解决了我的问题。但是我对SSL之类的东西一无所知。您能否帮助我了解它实际上解决了我的问题。

如果可能,请向我推荐任何有用的资源,以了解有关安全性和证书的信息。我是新来的。

谢谢!

注意:我确实通过链接-openssl,python请求错误:“证书验证失败”

我的问题与链接中的问题不同,因为我想知道在安装certifi软件包或运行Install\ Certificates.command该错误时实际发生了什么。我对证券知之甚少。

Ayo*_*oub 128

对于仍然想知道如何解决此问题的任何人,我通过安装“ Install Certificates.command”获得了我的

这是我的做法,

安装 Certificates.commad 位置

只需双击该文件等待它安装,就我而言,您就可以开始了

  • 具体如何安装呢?用酿造?请解释 (12认同)
  • 对于brew,这对我有用:`security find-certificate -a -p > ~/all_mac_certs.pem; 导出 SSL_CERT_FILE=~/all_mac_certs.pem; 导出 REQUESTS_CA_BUNDLE=~/all_mac_certs.pem` (6认同)
  • 它对我很有帮助。我遇到了同样的问题(macOS high Sierra + Python 3.7)。谢谢你! (4认同)
  • 它是一个“.command”文件,这意味着您只需双击它,它就会在终端中运行。 (3认同)
  • @JosephAstrahan 它是来自 www.python.org 的标准 python 安装包。这也是官方的 python 版本(我通常安装这个而不是自制的版本) (3认同)
  • @Pynchia 运行 `terminal > cd /Applications/{Python3.x}` 然后运行 ​​`terminal > ./Install\ Certificates.command` (3认同)
  • 但是你从哪里得到这个文件呢? (2认同)

Ale*_*exa 61

创建从操作系统证书到 Python 的符号链接对我有用:

ln -s /etc/ssl/* /Library/Frameworks/Python.framework/Versions/3.9/etc/openssl
Run Code Online (Sandbox Code Playgroud)

(我在 macOS 上,使用pyenv

  • 我通过brew使用Python 3.9.3,对我来说命令是`ln -s /etc/ssl /usr/local/etc/openssl@1.1` (5认同)
  • 它适用于 mac Air M1。 (4认同)

Zgp*_*ace 28

环境:Mac、Python 3.10、iTerm、

  1. 在Finder中搜索:安装Certificates.command
    在此输入图像描述
  2. 获取信息 在此输入图像描述
  3. 打开方式:iTerm.app
    在此输入图像描述
  4. 双击“安装证书.命令”

等待安装证书。解决这个问题。


Gal*_*tor 22

由于问题没有标签 [macos] 我在 ubuntu 下发布了同一问题的解决方案:

sudo apt install ca-certificates
sudo update-ca-certificates --fresh
export SSL_CERT_DIR=/etc/ssl/certs
Run Code Online (Sandbox Code Playgroud)

解决方案来自Github 上的Zomatree


小智 17

这在 Mac 操作系统上对我有用:

ln -s /etc/ssl/* /Library/Frameworks/Python.framework/Versions/Current/etc/openssl/
Run Code Online (Sandbox Code Playgroud)

  • 通过额外的支持信息可以改进您的答案。请[编辑]添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以[在帮助中心](/help/how-to-answer)找到有关如何写出好的答案的更多信息。 (5认同)
  • 运行了那个确切的命令,它对我有用!谢谢 (2认同)

wan*_*ang 10

我想提供一个参考。我使用 cmd + 空格,然后键入Install Certificates.command,然后按 Enter。片刻后,弹出命令行界面开始安装。

 -- removing any existing file or link
 -- creating symlink to certifi certificate bundle
 -- setting permissions
 -- update complete
Run Code Online (Sandbox Code Playgroud)

最后,它修复了错误。


Ken*_*Ken 9

This worked in all OS:

import ssl
import certifi

urlopen(request, context=ssl.create_default_context(cafile=certifi.where()))
Run Code Online (Sandbox Code Playgroud)


Mil*_*vić 9

Certifi提供 Mozilla\xe2\x80\x99s 精心策划的根证书集合,用于验证 SSL 证书的可信度,同时验证 TLS 主机的身份。它是从Requests项目中提取的。

\n
pip install certifi\n
Run Code Online (Sandbox Code Playgroud)\n

或者运行下面的程序代码:

\n
# install_certifi.py\n#\n# sample script to install or update a set of default Root Certificates\n# for the ssl module.  Uses the certificates provided by the certifi package:\n#       https://pypi.python.org/pypi/certifi\n\nimport os\nimport os.path\nimport ssl\nimport stat\nimport subprocess\nimport sys\n\nSTAT_0o775 = ( stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR\n             | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP\n             | stat.S_IROTH |                stat.S_IXOTH )\n\n\ndef main():\n    openssl_dir, openssl_cafile = os.path.split(\n        ssl.get_default_verify_paths().openssl_cafile)\n\n    print(" -- pip install --upgrade certifi")\n    subprocess.check_call([sys.executable,\n        "-E", "-s", "-m", "pip", "install", "--upgrade", "certifi"])\n\n    import certifi\n\n    # change working directory to the default SSL directory\n    os.chdir(openssl_dir)\n    relpath_to_certifi_cafile = os.path.relpath(certifi.where())\n    print(" -- removing any existing file or link")\n    try:\n        os.remove(openssl_cafile)\n    except FileNotFoundError:\n        pass\n    print(" -- creating symlink to certifi certificate bundle")\n    os.symlink(relpath_to_certifi_cafile, openssl_cafile)\n    print(" -- setting permissions")\n    os.chmod(openssl_cafile, STAT_0o775)\n    print(" -- update complete")\n\nif __name__ == \'__main__\':\n    main()\n
Run Code Online (Sandbox Code Playgroud)\n

Brew 尚未运行适用于 Mac 的 Python3 捆绑包中的 Install Certificates.command。

\n


小智 9

突然我开始在 Windows 环境中遇到这个问题。更糟糕的是,当我运行 pip 时它也出现了,所以问题不在于远程服务器证书。

在尝试了许多不同的事情之后,我找到了结合多个答案的点滴解决方案:

  • 将可信主机添加到 pip.ini: pip config set global.trusted-host "pypi.org files.pythonhosted.org pypi.python.org" (仅作为 pip install 参数传递不起作用)

  • 更新系统证书: pip install pip-system-certs (安装 python-certifi-win32 不起作用)

现在 https 请求又可以工作了 \o/

  • 我的公司使用 Zscaler,这就是全部。谢谢奥雷斯。 (2认同)

Max*_*Max 8

在我的例子中,此错误的原因是 OPENSSLDIR 设置为不包含实际证书的路径,可能是由某些升级/重新安装引起的。

要验证这一点(如果您可能遇到这种情况),请尝试运行:

openssl s_client -CApath /etc/ssl/certs/ -connect some-domain.com:443
Run Code Online (Sandbox Code Playgroud)

如果删除-CApath /etc/ssl/certs/并收到20错误代码,则这可能是原因。您还可以通过运行来检查 OPENSSSLDIR 设置的内容openssl version -a

由于更改 OPENSSLDIR 需要重新编译,我发现最简单的解决方案是在现有路径中创建符号链接:ln -s /etc/ssl/certs your-openssldir/certs


Raf*_*ffi 7

我在OSX上遇到了同样的问题,而我的代码在Linux上完全没问题,您给出了问题的答案!

在检查了您指向的文件后/Applications/Python 3.7/Install Certificates.command,事实证明此命令将默认Python安装的根证书替换为通过certifi软件包提供的根证书。

certifi是一组根证书。每个SSL证书都依赖一个信任链:您信任一个特定的证书,因为您信任该证书的父级,也信任该父级,等等。在某些时候,没有“父级”证书,而这些证书是“根”证书。对于那些用户,除了捆绑普遍信任的根证书(通常是大型的信任公司,例如“ DigiCert”),没有其他解决方案。

例如,您可以在浏览器的安全设置中查看根证书(例如,对于Firefox->首选项->隐私和安全->查看证书->权威)。

回到最初的问题,在运行.command文件之前,执行此操作会为我返回全新安装的空白列表:

import os
import ssl                                        
openssl_dir, openssl_cafile = os.path.split(      
    ssl.get_default_verify_paths().openssl_cafile)
# no content in this folder
os.listdir(openssl_dir)
# non existent file
print(os.path.exists(openssl_cafile))
Run Code Online (Sandbox Code Playgroud)

这意味着在OSX上没有Python安装的默认证书颁发机构。可能的默认值正是certifi软件包提供的默认值。

之后,您只需创建一个具有以下默认值的SSL上下文即可(certifi.where()给出证书颁发机构的位置):

import platform
# ...

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS)
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.check_hostname = True
ssl_context.load_default_certs()

if platform.system().lower() == 'darwin':
    import certifi
    ssl_context.load_verify_locations(
        cafile=os.path.relpath(certifi.where()),
        capath=None,
        cadata=None)
Run Code Online (Sandbox Code Playgroud)

并向urlpython 发送请求,如下所示:

import urllib
# previous context
https_handler = urllib.request.HTTPSHandler(context=ssl_context)

opener = urllib.request.build_opener(https_handler)
ret = opener.open(url, timeout=2)
Run Code Online (Sandbox Code Playgroud)

  • 您写道:`os.path.exists(openssl_cafile)`。这不应该是“os.path.exists(os.path.join(openssl_dir, openssl_cafile))”吗? (4认同)
  • @bli 我编辑了答案以进行修复 (2认同)

net*_*ink 5

我在 Linux 上使用 conda 时遇到错误。我的解决方案很简单。

conda install -c conda-forge certifi
Run Code Online (Sandbox Code Playgroud)

我不得不使用 conda forge,因为默认的证书似乎有问题。


小智 5

对于那些仍然存在此问题的人: - MacOS 上的 Python 3.6(还有其他一些版本?)带有自己的 OpenSSL 私有副本。这意味着系统中的信任证书不再被 Python ssl 模块用作默认值。要解决这个问题,您需要在系统中安装一个certifi包。

您可以尝试通过两种方式来做到这一点:

1) 通过画中画:

pip install --upgrade certifi
Run Code Online (Sandbox Code Playgroud)

2) 如果它不起作用,请尝试运行 Python 3.6 for Mac 附带的 Cerificates.command:

open /Applications/Python\ 3.6/Install\ Certificates.command
Run Code Online (Sandbox Code Playgroud)

无论如何,您现在应该安装了证书,并且 Python 应该能够通过 HTTPS 进行连接而不会出现任何问题。

希望这有帮助。


Var*_*mar 5

在开头粘贴以下代码:

# paste this at the start of code
import ssl 

try:
    _create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
    pass
else:
    ssl._create_default_https_context = _create_unverified_https_context
Run Code Online (Sandbox Code Playgroud)

  • 不要这样做!“我家的钥匙坏了!只要一直把门锁上就可以了。” (13认同)
  • 我的假设是否正确,这可以避免检查 SSL 证书的有效性? (3认同)
  • 这会跳过证书验证。 (2认同)