我正在致力于实现一个使用 API 的 Web 应用程序。在响应期间,API 服务器通过 X509 证书链接发送(采用 PEM 格式,由签名证书和一个或多个中间证书组成到根 CA 证书),我必须下载并使用它来进行进一步验证。
在使用证书之前,我需要确保链中的所有证书结合起来以创建到受信任的根 CA 证书的信任链(以检测和避免任何恶意请求)。我在 python 中很难做到这一点,我对这个主题的研究没有产生任何有用的东西。
使用请求和 M2Crypto 可以轻松获取和加载证书
import requests
from M2Crypto import RSA, X509
mypem = requests.get('https://server.com/my_certificate.pem')
cert = X509.load_cert_string(str(mypem.text), X509.FORMAT_PEM)
但是,验证证书链是一个问题。为了使用像 openssl
这样的命令行实用程序,通过子进程之类的东西将证书写入磁盘对我来说是不可行的,所以它必须通过 python 完成。我也没有任何打开的连接,因此使用基于连接的验证解决方案(如此答案/线程中提到的: https ://stackoverflow.com/a/1088224/4984533)也不起作用。
在另一个关于这个问题的话题上(在 https://stackoverflow.com/a/4427081 ),abbot 解释说 m2crypto 不能做这个验证,并说他已经写了一个扩展来允许验证(使用模块 m2ext
) 但他的补丁似乎从来没有工作过,即使我知道它是有效的,也总是返回 false :
from m2ext import SSL
ctx = SSL.Context()
ctx.load_verify_locations(capath='/etc/ssl/certs/') # I have run c_rehash in this directory to generate a list of cert files with signature based names
if not ctx.validate_certificate(cert): # always happens
print('Invalid certificate!')
在此处的类似线程上也有此答案 https://stackoverflow.com/a/9007764/4984533 其中 John Matthews 声称编写了一个补丁可以做到这一点,但不幸的是补丁链接现在已经失效 - 无论如何是对该线程的评论,指出该补丁不适用于 openssl 0.9.8e。
所有与验证 python 中的证书信任链相关的答案似乎都链接到死补丁或返回 m2ext
。
有没有一种简单直接的方法来验证我在 Python 中的证书信任链?
原文由 speznot 发布,翻译遵循 CC BY-SA 4.0 许可协议
虽然 Avi Das 的响应对于使用单个叶证书验证单个信任锚的简单情况是有效的, 但它信任中间证书。这意味着在发送中间件以及客户端证书的情况下,整个链都是可信的。
不要这样做。 pyOpenSSL 测试中发现的代码存在缺陷!
我在 Python 的 cryptography-dev 邮件列表中找到了这个线程(链接回这个答案): https ://mail.python.org/pipermail/cryptography-dev/2016-August/000676.html
它包括示例说明为什么这是一个糟糕的想法。我怎么强调都不为过: _通过信任中间体来验证你的链类似于根本不执行任何检查_。
话虽如此,您 如何 在 Python 中验证证书链?我找到的最佳替代方案是 https://github.com/wbond/certvalidator ,它似乎可以完成这项工作。
还有一些有缺陷的替代方案:
这是一些受人尊敬的 Python 密码学库的当前状态:
此时这两个线程似乎都过时了。
我知道这与问题的情况不符,但是: 如果您在 TLS 套接字中使用证书验证来构建某些东西,只需使用 Python 中已有的模块即可。 永远不要重新发明轮子,尤其是在密码学方面。加密很难;唯一容易的事情就是把它搞砸。