如何在 Python 中验证/验证 X509 证书信任链? [英] How to validate / verify an X509 Certificate chain of trust in Python?

查看:86
本文介绍了如何在 Python 中验证/验证 X509 证书信任链?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力实现一个利用 API 的 Web 应用程序.在响应期间,API 服务器通过链接发送到 X509 证书(采用 PEM 格式,由签名证书和根 CA 证书的一个或多个中间证书组成),我必须下载并使用该证书进行进一步验证.

I am working on implementing a web application that utilizes an API. During a response, the API server sends over a link to an X509 certificate (in PEM format, composed of a signing certificate and one or more intermediate certificates to a root CA certificate ) that I must download and use to do further verification.

在使用证书之前,我需要确保链中的所有证书结合起来以创建到受信任的根 CA 证书的信任链(以检测并避免任何恶意请求).我在 python 中很难做到这一点,我对该主题的研究没有产生任何有用的东西.

Before using the certificate, I need to ensure that all certificates in the chain combine to create a chain of trust to a trusted root CA certificate (to detect and avoid any malicious requests). I am having a hard time doing this in python and my research into the subject is not yielding anything useful.

使用请求和 M2Crypto 可以轻松获取和加载证书

The certificate is easily grabbed and loaded using requests and 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 这样的命令行实用程序,我将证书写入磁盘是不可行的,比如 subprocess,所以它必须通过 python 完成.我也没有任何打开的连接,所以使用基于连接的验证解决方案(就像在这个答案/线程中提到的那样:https://stackoverflow.com/a/1088224/4984533) 也不起作用.

However, validating the certificate chain is a problem. It is not feasible for me to write the certificate to disk in order to use a command line utility like openssl through something like subprocess, so it must be done through python. I also do not have any open connections and so using a connection based validation solution (like is mentioned in this answer / thread: https://stackoverflow.com/a/1088224/4984533) will not work either.

关于这个问题的另一个线程(在 https://stackoverflow.com/a/4427081)abbot 解释说 m2crypto 是无法进行此验证,并说他编写了一个扩展来允许验证(使用模块 m2ext),但他的补丁似乎从来没有工作,即使我知道它是有效的,也总是返回 false:

On another thread about this problem (at https://stackoverflow.com/a/4427081) abbot explains that m2crypto is incapable of doing this validation and says that he has written an extension to allow validation (using the module m2ext) but his patch never seems work, always returning false even though I know it's valid:

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.

There's also this answer on a similar thread here https://stackoverflow.com/a/9007764/4984533 in which John Matthews claims to have a patch written which will do it, but unfortunately the patch link is now dead -- and anyway there is a comment on that thread stating that the patch did not work with openssl 0.9.8e.

与在 python 中验证证书信任链相关的所有答案似乎都链接到死补丁或回到 m2ext.

All answers relating to validating a certificates chain of trust in python seem to either link to the dead patch or go back to m2ext.

是否有一种简单、直接的方法可以在 Python 中验证我的证书信任链?

Is there a simple, straightforward way to go about validating my certificates chain of trust in Python?

推荐答案

虽然 Avi Das 的响应适用于验证单个叶证书的单个信任锚的微不足道的情况,它将信任置于中间证书.这意味着在发送中间件以及客户端证书的情况下,整个链都是可信的.

While the response of Avi Das is valid for the trivial case of verifying a single trust anchor with a single leaf certificate, it places trust in the intermediate certificate. That means that in the case where the intermediate is sent, as well as the client certificate, the entire chain is trusted.

不要这样做.在pyOpenSSL的测试中发现的代码有缺陷!

Do not do this. The code found in pyOpenSSL's tests are flawed!

我在 Python 的 cryptography-dev 邮件列表(链接回这个答案)上找到了这个线程:https://mail.python.org/pipermail/cryptography-dev/2016-August/000676.html

I found this thread on Python's cryptography-dev mailing lists (which links back to this answer): https://mail.python.org/pipermail/cryptography-dev/2016-August/000676.html

我们看到这段代码没有区分 root_cert 和中间的.如果我们查看文档,add_cert 本身添加了一个trusted 证书(也许 add_trusted_cert 是一个更好的名字?).

We see this code makes no distinction between the root_cert and the intermediate. If we look at the documentation, add_cert itself adds a trusted cert (maybe add_trusted_cert would be a better name?).

它包含了为什么这是一个糟糕的想法的例子.我再怎么强调都不为过:通过信任中间人来验证您的链类似于根本不执行任何检查.

It includes examples on why this is a terrible idea. I can not stress this enough: verifying your chain by trusting the intermediates is similar to not performing any check at all.

话虽如此,您如何在 Python 中验证证书链?我发现的最佳替代方法是 https://github.com/wbond/certvalidator,它似乎可以做到工作.

Having said that, how do you verify a certificate chain in Python? The best alternative I found is https://github.com/wbond/certvalidator, which seems to do the job.

还有一些有缺陷的替代方案:

There are also some flawed alternatives:

  • https://github.com/alex/x509-validator, which explicitly states that it is not safe to use.
  • https://github.com/pyca/cryptography/issues/1660#issuecomment-75075319, which does some sort of checking, but I'm not sure it works as intended

这是一些受人尊敬的 Python 加密库的当前状态:

This is the current state for some respectable Python cryptography libraries:

  • https://github.com/pyca/pyopenssl/pull/473 discusses a pull request to incorporate chain verification in pyopenssl, which has not been merged yet.
  • https://github.com/pyca/cryptography/issues/2381 is an issue requesting a similar feature to the cryptography module, but it is still unresolved

此时两个线程似乎都过时了.

Both threads seem stale at this time.

我知道这与问题的情况不符,但是:如果您正在使用 TLS 套接字中的证书验证构建某些东西,只需使用 Python 中已有的模块. 永远不要重新发明轮子,特别是关于密码学.加密很难;唯一容易的事情就是把它搞砸.

I know this does not match the question's case, but: if you are building something using certificate validation in TLS sockets, just use the modules already available in Python. Never re-invent the wheel, especially regarding cryptography. Crypto is hard; the only easy thing about it is messing it up.

这篇关于如何在 Python 中验证/验证 X509 证书信任链?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆