【问题标题】:Can someone explain this callback function for SSL certificates?有人可以解释 SSL 证书的回调函数吗?
【发布时间】:2016-08-02 09:50:03
【问题描述】:

如果这不是正确的 SO(信息安全或加密),我马上道歉。无论如何,我正在尝试弄清楚如何在 Python 中验证 SSL 证书客户端。我发现了一个回调函数here,看起来和我在网上看到的其他函数很相似。但是,在我的代码中,我不确定它是如何(或为什么,真的)工作的。当我运行我的代码时它似乎可以工作,但是为什么(在 PyCharm 中)前四个参数是灰色的,而只有第五个参数是白色的?有没有办法可以使用这个回调函数来检查特定的证书错误?

这是我运行时的输出

Certs are fine
Certs are fine
Certs are fine
b'HTTP/1.1 200 OK\r\nDate: Tue, 12 Apr 2016...etc

我假设“证书没问题”的每一行都在验证链中的每个证书?

import socket
from OpenSSL import SSL

HOST = "www.google.com"
PORT = 443

def verify_callback(connection, x509, errnum, errdepth, ok):
        if not ok:
            print("Bad Certs")
        else:
            print("Certs are fine")
        return ok


context = SSL.Context(SSL.TLSv1_2_METHOD)
context.load_verify_locations("cacerts.pem")
context.set_options(SSL.OP_NO_SSLv2)
context.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback)


# create socket and connect to server
sock = socket.socket()
sock = SSL.Connection(context, sock)
sock.connect((HOST, PORT))
sock.do_handshake()
sock.sendall("GET / HTTP/1.1\r\n\r\n")

【问题讨论】:

  • 您是否考虑过查阅文档?
  • 是的,但它对用户不太友好,尤其是像我这样的加密新手。
  • 访问一些没有正确实现SSL的网站,打印x509, errnum, errdepth的内容?
  • 我目前正在尝试自己找出答案,发现这篇文章很有用:blog.san-ss.com.ar/2012/05/…

标签: python-3.x ssl tls1.2 pyopenssl


【解决方案1】:

这里的pyOpenSSL docs 非常稀疏,但这个函数是对应OpenSSL 函数的包装,其文档是much better

verify_callback 函数用于控制设置 SSL_VERIFY_PEER 标志时的行为。它必须由应用程序提供并接收两个参数:preverify_ok 指示是否通过了相关证书的验证(preverify_ok=1)或未通过(preverify_ok=0)。 x509_ctx 是指向用于证书链验证的完整上下文的指针。

从最深的嵌套级别(根 CA 证书)开始检查证书链,并向上工作到对等方的证书。在每个级别检查签名和颁发者属性。每当发现验证错误时,错误号都会存储在 x509_ctx 中,并在 preverify_ok=0 时调用 verify_callback。通过应用 X509_CTX_store_* 函数 verify_callback 可以找到有问题的证书并执行其他步骤(参见示例)。如果未发现证书错误,则在进入下一个级别之前调用 verify_callback 并设置 preverify_ok=1。

verify_callback 的返回值控制着进一步验证过程的策略。如果 verify_callback 返回 0,则验证过程立即以“验证失败”状态停止。如果设置了 SSL_VERIFY_PEER,则会向对等方发送验证失败警报​​,并终止 TLS/SSL 握手。如果 verify_callback 返回 1,则继续验证过程。如果 verify_callback 始终返回 1,则 TLS/SSL 握手不会因验证失败而终止,并且将建立连接。然而,调用进程可以使用 SSL_get_verify_result(3) 或通过维护自己的由 verify_callback 管理的错误存储来检索最后一个验证错误的错误代码。

如果没有指定 verify_callback,将使用默认回调。它的返回值与 preverify_ok 相同,因此如果设置了 SSL_VERIFY_PEER,任何验证失败都会导致 TLS/SSL 握手终止并发出警告消息。

文档还有一个解释清楚的示例验证函数,用于检查被验证的链是否太长。如果链太长,则会记录错误,然后根据用户设置的值,回调要么返回 0 导致验证失败,要么返回 1(即忽略错误并继续验证)。

此外,this blog post 有一个 pyOpenSSL 示例,该示例仅检查几个特定错误并在它们发生时验证失败。

【讨论】:

    【解决方案2】:

    需要澄清的一些事情

    1. VERIFY_FAIL_IF_NO_PEER_CERT 只是被忽略,特别是在客户端上下文中。所以可以去掉。这仅在服务器上下文中使用。

    2. ok 属性是一个“预验证码”,如果预验证成功,则 ok=1,否则,ok=0。强调预验证,验证没有完成,这就是这个功能的目的。即按原样返回它会有效地跳过验证(您最好永远不要调用set_verify 并改用context.verify_mode)。

    3. verify_callback 的第 4 个属性是证书深度,而不是 errdepth,没有错误,它只是让您知道这是哪个对等证书的深度(见第 4 点)

    4. 您的verify_callback 将被多次调用,链中的每个对等证书一次。该顺序是由 openssl 为您预先确定的,因此您不需要将 subjectKeyIdentifier 与您在此枚举中尚未看到的对等证书 authorityKeyIdentifier 进行匹配。您可以相信 openssl 已为您完成了这项检查,您需要做的只是根据您的情况进行一些其他检查。

    又有什么意义呢?

    我们正在做自己的客户端证书身份验证,即我们需要根据客户端知道的可信信息检查某些服务器响应信息,即服务器响应是真实的

    客户知道什么样的事情?

    • 客户端应该有受信任的颁发者,因此您应该首先验证对等证书是否符合此预期
    • 客户也可能知道depth(参见第 3 点),即深度 3 是可以接受的,4 及以上则不可接受。我们可能知道我们有 3 个对等证书;根 CA(在根信任存储中)、服务器证书签署者(您为证书付费的人)和服务器证书(由签署它的 CA 生成)。因此 dpeth 为 3 所以 4 或更多应该返回 0
    • 客户端通常具有要提供给服务器的客户端证书,如果它应用零信任(真实的,而不是供应商名义上出售的),它需要为与之通信的每项服务提供一个证书,服务网格就是一个很好的例子。那么哪个证书是合适的?服务器可以给你一个提示,你可以使用sock.get_client_ca_list()阅读,但如果你盲目使用它,它可能是一个重新路由到恶意服务器的请求,即客户端证书身份验证具有任何安全特性,我们必须进行自己的验证,不管任何潜在的恶意影响。因此,将get_client_ca_list() 的值视为指导(如果发送了意外的值,它可能表示妥协)并且您必须根据您所知道的而不是要求您信任的内容提供适当的证书(如果它失败,它安全失败,不会连接到恶意服务器)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 2012-05-29
      • 2010-12-13
      相关资源
      最近更新 更多