【问题标题】:Certificate Authority for imaplib and poplib pythonimaplib 和 poplib python 的证书颁发机构
【发布时间】:2012-03-31 13:36:28
【问题描述】:

我正在使用 imaplib 和 poplib 执行使用 IMAPS 和 POP3S 的电子邮件收集,以实现安全连接。但据我所知,这两个库都没有使用 CA 来确认收到的证书的有效性。这是真的吗?如果是,是否可以将 imaplib 或 poplib 设置为使用 CA?

如果不是真的并且他们确实使用 CA,有人可以告诉我 imaplib/poplib 是如何做到的吗?

谢谢。

【问题讨论】:

    标签: python imaplib poplib


    【解决方案1】:

    imaplib.py 的快速检查表明它使用 ssl.wrap_socket() 来实现 IMAP_SSL() 调用。对 wrap_socket() 调用的调用仅提供 3 个参数,并且不传递所需的参数 ca_cert,这是您验证 CA 所需要的。

    您可以从 IMAP4_SSL 继承,并覆盖 open() 方法以传入所需的 ca_cert。查看http://docs.python.org/library/ssl.html 了解更多信息。

    可能是这样的:

    class IMAP4_SSL_CA_CHECKER(IMAP4_SSL):
        def open(self, host = '', port = IMAP4_SSL_PORT, ca_certs = None):
            self.host = host
            self.port = port
            self.sock = socket.create_connection((host, port))
            self.sslobj = ssl.wrap_socket(self.sock, self.keyfile, 
                              self.certificate, ca_certs=ca_certs)
            self.file = self.sslobj.makefile('rb')
    

    【讨论】:

    • 谢谢。我是 Python 的新手,所以只是为了确认我正确理解了你的建议。我想覆盖 imaplib 的 ssl.wrap_socket() 以允许设置“cert_reqs”参数(例如,将其设置为“CERT_REQUIRED”)然后将“ca_certs”设置为指向包含 CA 的文件(我构造)? (假设我理解正确)这听起来不是一个太糟糕的解决方法:)
    • 我不确定您是否要指定“cert_reqs”(您可以这样做——但该参数解决了一个微妙的不同问题)。它告诉客户端要求服务器提供证书并且它是有效的。可以说这是一件好事,如果你确定双方都会同意,但如果你想要更通用的东西,这个假设可能会落空。
    • 看起来 self.certificate 必须替换为 self.certfile 才能正常工作。
    • 看起来这不起作用。我使用ca_certs 进行了测试,它指向与我连接到的服务器所使用的根证书不同的根证书,并且我使用与证书中使用的不同的主机名连接到服务器。其中任何一个都应该导致证书验证错误,但事实并非如此。
    • 由于 wrap_socket 从未被告知主机名是什么,因此无法验证证书。
    【解决方案2】:

    我又想到了一个想法。 python ssl 库构建在 OpenSSL 之上。如果您要开始要求服务器提供证书并且它们是有效的,那么您将很快遇到与证书存储相关的各种 Unix 版本的问题。

    如果您碰巧在已安装 Mozilla/Firefox 的系统上工作,则证书存储可能设置正确。但事实并非如此,您需要花费几天的时间才能使其正常工作。

    这个链接对我们帮助很大:http://www.madboa.com/geek/openssl/

    特别关注这个链接:http://www.madboa.com/geek/openssl/#verify-system

    任何使用 openssl 工作的开发人员都应该为该站点添加书签。这有点简洁,但每一个条目都值得一提!

    【讨论】:

    • 再次感谢您的帮助。我将对这些文档进行全面阅读,以充分了解我正在处理的内容。我已经用一些额外的位实现了你提到的类,包括: - 添加 cert_reqs=CERT_REQUIRED, ca_certs='/etc/.../ca-bundle.crt' 到 def open 并将它们传递给 self.sslobj。我还导入了所需的 ssl 位并设置了“imaplib.IMAP4_SSL = IMAP4_SSL_CA_CHECKER”。
    • 它似乎在做正确的事情,但现在我得到“SSLError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed”。所以看起来我需要解决我的代码从我的 Dovecot 服务器接受证书。是时候开始阅读 OpenSSL 了 :)
    【解决方案3】:

    因为 IMAP4SSL.open 是从 IMAP 调用的。init上面的解决方案没有帮助,因为用户没有调用 open()。 您可以将 IMAP.init 覆盖为...

    简短:仅扩展 open() 的参数是不够的。

    我用过注射:

    def IMAP4SSL_open(self, host = '', port = imaplib.IMAP4_SSL_PORT):
        ... own implementation ...
        wrap_socket( ... cert_reqs=ssl.CERT_REQUIRED ... )
    imaplib.IMAP4_SSL.__dict__['open']=IMAP4SSL_open
    

    【讨论】:

      【解决方案4】:

      我目前正在朝这个方向发展。

      以下代码将starttls 添加到 IMAP。连接后只需拨打server.starttls()。请务必连接到正常的 IMAP 端口。

      import imaplib,ssl
      def IMAP_starttls(self, keyfile=None, certfile=None,cert_reqs=ssl.CERT_NONE,ca_certs=None):
        if not 'STARTTLS' in self.capabilities:
          raise self.error("STARTTLS extension not supported by server.")
        (resp, reply) = self._simple_command("STARTTLS")
        self.sock = ssl.wrap_socket(self.sock, keyfile, certfile,cert_reqs=cert_reqs,ca_certs=ca_certs)
        self.file = self.sock.makefile('rb')
      
      imaplib.IMAP4.__dict__['starttls']=IMAP_starttls
      imaplib.Commands['STARTTLS']=('NONAUTH',)
      

      PS:我想将其添加为注释,但代码太长了。

      【讨论】:

        猜你喜欢
        • 2014-12-26
        • 1970-01-01
        • 2018-06-19
        • 2012-04-18
        • 1970-01-01
        • 2011-07-28
        • 2016-01-01
        • 1970-01-01
        相关资源
        最近更新 更多