可以使用 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 包:
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
同样错误
requests.get(..., verify="/etc/ssl/certs/ca-certificates.crt")
同样错误
- 切换到 httpx + 自定义 SSL 上下文,如 the docs 中所述,同样的错误
- 已尝试
truststore
as discussed in this httpx issue,同样的错误
如何让 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。您应该尝试使用您的浏览器下载完整链并重试。
我可以使用 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 包:
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
同样错误requests.get(..., verify="/etc/ssl/certs/ca-certificates.crt")
同样错误- 切换到 httpx + 自定义 SSL 上下文,如 the docs 中所述,同样的错误
- 已尝试
truststore
as discussed in this httpx issue,同样的错误
如何让 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。您应该尝试使用您的浏览器下载完整链并重试。