3

每次客户端连接到服务器时,我都会收到输入 PEM 密码短语的提示。我只想在服务器启动时输入它,而不必再次输入它。Twisted Matrix 框架只需要启动时的密码,为什么不用 gevent?还是我使用 gevent 错误?如果我使用不需要 PEM 密码短语的证书,下面的代码可以正常工作,但我想使用带有密码短语的证书。

from gevent.server import StreamServer
from gevent.pool import Pool
from gevent import monkey

class SocketPool(object):

    def __init__(self): self.pool = Pool(1000)

    def listen(self, socket):
        while True:
            line = socket.recv(1024)
            if not line: break 
            print line
            socket.close()
            break

    def add_handler(self, socket, address):
        print "connection made:", address
        if self.pool.full(): raise Exception("At maximum pool size")
        else: self.pool.spawn(self.listen, socket)

    def shutdown(self): self.pool.kill()

monkey.patch_all()
sockPool = SocketPool() 
server = StreamServer(('', 5000), sockPool.add_handler, keyfile='key.pem', certfile='cert.pem')
server.serve_forever()
4

1 回答 1

5

在 python 2.7 上似乎没有一种简单的方法来解决这个问题。在内部,gevent.server使用从 C 调用 OpenSSL 库的 pythonssl模块。该_ssl.sslwrap()函数为每次调用创建一个新的 SSLContext,这就是每次建立连接时都会提示您输入密钥密码的原因。

Twisted 使用 pyOpenSSL 而不是ssl模块。在 pyOpenSSL 中,您首先创建 SSLContext,并且每次建立连接时都会使用该单个上下文。因此,使用 Twisted 时只会提示您输入一次密码。

Python 3.2 添加了一个带有方法的ssl.SSLContext类。wrap_socket()如果您使用的是此版本或更高版本,那么您可以修补 gevent 代码以使其更像 Twisted,即使用单个 SSLContext 并将调用替换_ssl.sslwrap()为对wrap_socket()方法的调用。不过,gevent 似乎没有移植到 python3

您可以通过在前面放置一个 SSL 代理来卸载 gevent 的 SSL 处理,因此到公共端口的传入 SSL 连接被代理到未加密内部端口上的 gevent 服务器。您可以使用 Twisted 编写自己的代理或使用stunnel 之类的专用代理。但是,这可能会否定您最初想使用 gevent 的部分或全部原因。

您可以修补您的_ssl模块以缓存 SSLContexts 或使用另一种接受密码的方式。 _ssl在 python 2.7 中使用默认密码回调,它以交互方式提示输入密码。这不会那么困难,但它要求您至少了解一点 C、python C API 和 OpenSSL API,而且您必须在部署的任何地方构建和覆盖模块。

您可以使用自己的代码修补 gevent 以使用 SSL 包装套接字。这可以完全在 python 中使用 pyOpenSSL 之类的库来完成,但要做到这一点可能需要大量的工作。

最后,您可以只使用未加密的密钥。也许将密钥放在 RAM 磁盘或加密文件系统(或两者)上可以满足您的任何安全要求。

于 2013-06-24T15:55:54.173 回答