我正在将我的 Python 2 代码移植到 Python 3。这个特定部分涉及在 Python 3 中运行我的代码时我的本地机器发布到网页(在 Python 2 中一切正常)。我认为我的问题的根本原因是我这边的证书未能通过服务器的身份验证。以下是我看到的错误。
Error(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1056)')))
request Error: HTTPSConnectionPool(host='my/personal.server', port=443): Max retries exceeded with url: my/personal/url/and/data (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1056)')))
错误发生在我程序中的 requests.post(url, headers)
行。我已经确定服务器 URL 是正确的。
我认为问题如下。在 macOS 的 native Python 2 环境(我以前编写过的代码)中,ssl
模块与位于 Python 3 用于导入的目录中的模块不同。我的问题是:
- 我的 Python 3 实例可以使用
LibreSSL
吗? - 如果没有,当我在 Python 3 中导入
ssl
模块时,如何传递cafile
和其他路径参数?
FWIW,我从 Python.org 下载了 Python 3。
python 2
⇒ python
Python 2.7.10 (default, Feb 22 2019, 21:55:15)
[GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl, sys
>>> sys.executable
'/usr/bin/python'
>>> ssl.OPENSSL_VERSION
'LibreSSL 2.2.7'
>>> ssl.get_default_verify_paths()
DefaultVerifyPaths(cafile='/private/etc/ssl/cert.pem', capath='/private/etc/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/private/etc/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/private/etc/ssl/certs')
python 3
⇒ python3
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 16:52:21)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl, sys
>>> sys.executable
'/usr/local/bin/python3'
>>> ssl.OPENSSL_VERSION
'OpenSSL 1.1.0j 20 Nov 2018'
>>> ssl.get_default_verify_paths()
DefaultVerifyPaths(cafile='/Library/Frameworks/Python.framework/Versions/3.7/etc/openssl/cert.pem', capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/Library/Frameworks/Python.framework/Versions/3.7/etc/openssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/Library/Frameworks/Python.framework/Versions/3.7/etc/openssl/certs')
我相信这就是我出现此错误的原因,尽管我不是 100% 确定。欢迎任何其他指示或输入!
编辑
按照 ivan_pozdeev 建议的重复问题,我可以运行 openssl s_client -connect mywebsite.com:443 -verify 9
并得到 Verify return code: 0 (ok)
。虽然我没有在我的 python/bash 脚本中直接调用 openssl
,但我已经能够验证我的 Python 2 配置是否有效。
⇒ openssl
OpenSSL> version
LibreSSL 2.6.5
OpenSSL> ca
Using configuration from /private/etc/ssl/openssl.cnf
我正在研究如何利用我在 Python 3 解释器及其库中所做的上述工作。然而,这似乎更像是一个测试,看看我是否可以与服务器对话,而不是解决参数/环境问题。
编辑 2
也许这是一个调查时间太长的案例,但我发现了一些奇怪的事情。上面的 Python 2/3 实例是在 zsh
中完成的,而不是在我的程序中。当我使用这些 print
语句运行我的脚本时,我得到了这个 ssl
信息:
python 2
import ssl
print ssl.OPENSSL_VERSION
print ssl.get_default_verify_paths()
输出
LibreSSL 2.2.7
DefaultVerifyPaths(cafile='/usr/local/etc/openssl/cert.pem', capath='/private/etc/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/private/etc/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/private/etc/ssl/certs')
python 3
import ssl
print(ssl.OPENSSL_VERSION)
print(ssl.get_default_verify_paths())
输出
OpenSSL 1.1.0j 20 Nov 2018
DefaultVerifyPaths(cafile=None, capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/Library/Frameworks/Python.framework/Versions/3.7/etc/openssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/Library/Frameworks/Python.framework/Versions/3.7/etc/openssl/certs')
Python 2 脚本打印出我所期望的。 Python 3 脚本将我的 cafile
参数设置为 None
,这与我在zsh
。我在我的 bash
脚本中使用 python
和 python3
别名来调用我的 Python 脚本,并且绝对确定它们引用与我的 相同的解释器zsh
。这到底是怎么回事?
最佳答案
发现可以通过我包装在 python 脚本中的 bash
shell 脚本在环境中设置参数。
export SSL_CERT_FILE=/usr/local/etc/openssl/cert.pem
export REQUESTS_CA_BUNDLE=/usr/local/etc/openssl/cert.pem
我想我的脚本之前只是在查看一个空的证书目录?无论如何,它现在有效。我写的路径是默认情况下 OpenSSL 拥有其证书的位置。
关于python - 如何更改Python3中ssl模块中的 'cafile'参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55736855/