python - 如何从 python-requests 响应/异常对象访问对等方的证书链?
问题描述
我使用python-requests与 HTTPS Web 服务通信,其中一些提供不完整的证书 X509 链。我无法弄清楚如何访问无效/不完整的证书以便向用户解释错误。
这是https://ssllabs.com/ssltest说明的示例,其中服务器仅发送叶证书,而不是验证所需的中间证书,但从certifi
的根 CA 存储中丢失:
当我尝试连接python-requests时,我得到一个不是很有用的异常:
request.get('https://web.service.com/path')
SSLError: HTTPSConnectionPool(host='web.service.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))
显然,我可以使用单独的工具来找出任何特定情况下的问题(例如gnutls-cli
,openssl s_client
SSLLabs 等)。
但是,我真正想做的是能够在我的 Python 代码中捕捉和诊断证书链的问题,以便向用户呈现更具体的错误消息。这个答案暗示了响应对象的猴子补丁;它不是特别优雅,但它可以工作——尽管只有在成功返回响应对象时,而不是在异常的情况下。
requests
当请求无法验证证书链本身时,将对等方的证书链保存在返回的异常对象中的最简洁方法是什么 ?
解决方案
举requests.get("https://151.101.1.69") # stackoverflow's ip
个例子:
try:
requests.get("https://151.101.1.69")
except requests.exceptions.SSLError as e:
cert = e.args[0].reason.args[0]._peer_cert
然后cert
是一个 dict 包含对等方的证书。由于我不是很熟悉SSL
,我不知道这是否足以满足您的情况。
顺便说一句,在这种情况下,错误是"hostname '151.101.1.69' doesn't match either of '*.stackexchange.com', ...omitted
. 我不确定您真实案例中的异常结构,因此您可能需要自己找到它。我认为它应该具有相同的名称_peer_cert
。
更新
握手失败时上述方法不起作用......但它仍然可以做到:
try:
requests.get("https://fpslinux1.finalphasesystems.com/")
except requests.exceptions.SSLError:
import ssl
import OpenSSL
cert = ssl.get_server_certificate(('fpslinux1.finalphasesystems.com', 443))
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
print(cert.get_issuer())
print(cert.get_subject().get_components())
是的,它有点脏,但我没有更好的方法,因为 ssl 套接字甚至不会从 C 级别返回无效证书:/
要使用OpenSSL
,您需要安装pyopenssl
。
推荐阅读
- xmpp - Openfire CallbackOnOffline 插件未触发 [plugin.callback_on_offline.url] 离线用户的 URL
- android - 如何在Android中将动画设置为进度条
- javascript - 为什么`card`元素不重复4次
- java - 为外部库的类提供前缀
- javascript - Angular 2为每个数组对象添加键和值
- vb.net - VB上的条件目录信息
- c# - 如何在不使用每个控制器的方法的情况下将一些 ViewData 附加到布局?
- python - 某些 WTForm 验证方法上的消息不闪烁
- sql - 扩大日期范围时,数组索引 1 超出范围(溢出)
- angular - Angular 6 中的多个承诺中的承诺?