证书验证失败:无法获取本地颁发者证书,没什么异常
我在用Python的requests库时遇到了一个错误:
证书验证失败:无法获取本地颁发者证书。
这是我的代码:
import requests
url = 'https://sha256.badssl.com'
cert_path = 'certificate.pem'
response = requests.get(url, verify=cert_path)
文件certificate.pem包含了:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
这是通过以下方式得到的:
openssl s_client -connect sha256.badssl.com:443
certificate.pem和我的main.py在同一个文件夹里。
我试过用绝对路径。
我尝试过Python版本3.10.12和3.12.2。
我已经查看过文档,也看过同样的问题,在这里。
我还尝试过换一个WiFi。
我没有运行任何代理。
2 个回答
我觉得你遇到了几个问题,因为 https://badssl.com 这个网站有有效的证书,所以你不应该在访问这个网址时出现证书错误。这说明你可能缺少一些基本的受信任证书颁发机构的列表。
那么,我们来仔细看看这个问题。
如果你通过下面的方式获取服务器的证书:
openssl s_client -connect sha256.badssl.com:443 < /dev/null > certificate
那么你会得到一个单独的证书:
$ grep BEGIN certificate
-----BEGIN CERTIFICATE-----
这个证书不是自签名证书:
$ openssl x509 -in certificate -noout -subject -issuer certificate
subject=CN = *.badssl.com
issuer=C = US, O = Let's Encrypt, CN = R3
这意味着在 requests.get
的 verify
参数中使用它是没有意义的;你需要的是颁发者的证书。当你使用 openssl s_client
来获取远程证书时,可能需要提供 -showcerts
选项,这样可以显示服务器发送的整个证书链:
openssl s_client -showcerts -connect sha256.badssl.com:443 < /dev/null > certificate
现在你会发现我们有多个证书:
$ grep BEGIN certificate
-----BEGIN CERTIFICATE-----
-----BEGIN CERTIFICATE-----
第一个证书是我们之前看到的,但第二个证书是:
subject=C = US, O = Let's Encrypt, CN = R3
issuer=C = US, O = Internet Security Research Group, CN = ISRG Root X1
如果我们把这个新文件当作我们的CA捆绑包使用,它就能正常工作:
>>> import requests
>>> requests.get('https://badssl.com/', verify='certificate')
<Response [200]>
值得注意的是,远程服务器提供的证书链可能不包括根证书。在这种情况下,你需要直接从证书颁发机构获取根证书(例如,https://letsencrypt.org/certificates/ 是 Let's Encrypt 的根证书)。
这个命令:
openssl s_client -showcerts -connect sha256.badssl.com:443 < /dev/null > certificate
会提供两个证书,但请求需要第三个证书。
如果想在Firefox浏览器上获取这个证书,可以按照以下步骤操作:
点击地址栏里的小锁图标
然后点击查看证书
在第三个证书部分,点击PEM(证书)
不过我不知道怎么用openssl获取这个证书。如果有人知道怎么做,那就太好了。