可以使用 curl 连接到 URL 但不能使用请求(即忽略我的 CA 包的请求?)

can connect to URL with curl but not with requests (i.e. requests ignoring my CA bundle?)

我可以使用 cURL 连接到某个 URL,在我安装相应的 SSL 证书后:

$ export MY_URL=https://www.infosubvenciones.es/bdnstrans/GE/es/convocatoria/616783
$ curl -vvvv $MY_URL  # Fails
$ sudo openssl x509 -inform pem -outform pem -in /tmp/custom-cert.pem -out /usr/local/share/ca-certificates/custom-cert.crt
$ sudo update-ca-certificates
$ curl -vvvv $MY_URL  # OK

但是,请求(或 httpx,或我使用的任何其他库)拒绝这样做:

In [1]: import os
   ...: import requests
   ...: requests.get(os.environ["MY_URL"])
---------------------------------------------------------------------------
SSLCertVerificationError                  Traceback (most recent call last)
...

SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)

我的理解是请求使用 certifi,因此这些自定义证书在此处不可用:

In [1]: import certifi

In [2]: certifi.where()
Out[2]: '/tmp/test_ca/.venv/lib/python3.10/site-packages/certifi/cacert.pem'

我已经尝试了很多东西,比如尝试使用系统 CA 包:

如何让 Python(请求、httpx、原始 ssl、任何东西)使用 cURL 成功使用的相同证书?

的启发,到目前为止唯一有效的方法是 verify=False。但我不想那样做。

In [9]: requests.get(
   ...:     my_url,
   ...:     verify=False,
   ...: )
/tmp/test_ca/.venv/lib/python3.10/site-packages/urllib3/connectionpool.py:1043: InsecureRequestWarning: Unverified HTTPS request is being made to host 'xxx'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings

我在我的系统上试过你的东西(Manjaro Linux,python 3.10)我可以建立连接。我从网站上下载了完整的证书链(使用我的浏览器)。之后我可以使用它:

r = requests.get(url=URL, verify=<path to pem file>)

并与

export REQUESTS_CA_BUNDLE=<path to pem>

r = requests.get(url=URL)

我尝试在 pyCharm 内导出。

所以 python 东西正在工作,您的证书可能有问题。如果没有这些东西,我会得到 ssl 错误(当然),因为 python 没有使用您提到的正确的系统证书。在我的 pem-file 中,我有 3 个证书。也许你只有1个,其他的都在global store里,这样curl就不需要完整的链了,取而代之的是python。您应该尝试使用您的浏览器下载完整链并重试。