【发布时间】:2012-03-31 13:36:28
【问题描述】:
我正在使用 imaplib 和 poplib 执行使用 IMAPS 和 POP3S 的电子邮件收集,以实现安全连接。但据我所知,这两个库都没有使用 CA 来确认收到的证书的有效性。这是真的吗?如果是,是否可以将 imaplib 或 poplib 设置为使用 CA?
如果不是真的并且他们确实使用 CA,有人可以告诉我 imaplib/poplib 是如何做到的吗?
谢谢。
【问题讨论】:
我正在使用 imaplib 和 poplib 执行使用 IMAPS 和 POP3S 的电子邮件收集,以实现安全连接。但据我所知,这两个库都没有使用 CA 来确认收到的证书的有效性。这是真的吗?如果是,是否可以将 imaplib 或 poplib 设置为使用 CA?
如果不是真的并且他们确实使用 CA,有人可以告诉我 imaplib/poplib 是如何做到的吗?
谢谢。
【问题讨论】:
对 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')
【讨论】:
self.certificate 必须替换为 self.certfile 才能正常工作。
ca_certs 进行了测试,它指向与我连接到的服务器所使用的根证书不同的根证书,并且我使用与证书中使用的不同的主机名连接到服务器。其中任何一个都应该导致证书验证错误,但事实并非如此。
wrap_socket 从未被告知主机名是什么,因此无法验证证书。
我又想到了一个想法。 python ssl 库构建在 OpenSSL 之上。如果您要开始要求服务器提供证书并且它们是有效的,那么您将很快遇到与证书存储相关的各种 Unix 版本的问题。
如果您碰巧在已安装 Mozilla/Firefox 的系统上工作,则证书存储可能设置正确。但事实并非如此,您需要花费几天的时间才能使其正常工作。
这个链接对我们帮助很大:http://www.madboa.com/geek/openssl/
特别关注这个链接:http://www.madboa.com/geek/openssl/#verify-system
任何使用 openssl 工作的开发人员都应该为该站点添加书签。这有点简洁,但每一个条目都值得一提!
【讨论】:
因为 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
【讨论】:
我目前正在朝这个方向发展。
以下代码将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:我想将其添加为注释,但代码太长了。
【讨论】: