我一直在寻找同样的东西。我知道 CherryPy 网站上有一些补丁。
我还在CherryPy SSL Client Authentication找到了以下内容。我没有将它与 CherryPy 补丁进行比较,但也许这些信息会有所帮助。
我们最近需要开发一个快速但有弹性的 REST 应用程序,发现 CherryPy 比其他 Python 网络框架(如 Twisted)更适合我们的需求。不幸的是,它的简单性缺少我们需要的一个关键特性,服务器/客户端 SSL 证书验证。因此,我们花了几个小时对当前版本 3.1.2 进行了一些快速修改。以下代码片段是我们所做的修改:
cherrypy/_cpserver.py
@@ -55,7 +55,6 @@ instance = None ssl_certificate = None ssl_private_key
= None
+ ssl_ca_certificate = None nodelay = True
def __init__(self):
cherrypy/wsgiserver/__init__.py
@@ -1480,6 +1480,7 @@
# Paths to certificate and private key files ssl_certificate = None ssl_private_key = None
+ ssl_ca_certificate = None
def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None, max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
@@ -1619,7 +1620,9 @@
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if self.nodelay: self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- if self.ssl_certificate and self.ssl_private_key:
+ if self.ssl_certificate and self.ssl_private_key and \
+ self.ssl_ca_certificate:
+ if SSL is None: raise ImportError("You must install pyOpenSSL to use HTTPS.")
@@ -1627,6 +1630,11 @@ ctx = SSL.Context(SSL.SSLv23_METHOD) ctx.use_privatekey_file(self.ssl_private_key) ctx.use_certificate_file(self.ssl_certificate)
+ x509 = crypto.load_certificate(crypto.FILETYPE_PEM,
+ open(self.ssl_ca_certificate).read())
+ store = ctx.get_cert_store()
+ store.add_cert(x509)
+ ctx.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, lambda *x:True) self.socket = SSLConnection(ctx, self.socket) self.populate_ssl_environ()
上述补丁需要在 CherryPy 服务器配置 server.ssl_ca_certificate 中包含一个新的配置选项。此选项标识将验证连接客户端的证书颁发机构文件,如果客户端没有提供有效的客户端证书,它将立即关闭连接。
我们的解决方案有优点和缺点,主要优点是如果连接的客户端没有提供有效的证书,它的连接会立即关闭。这有利于安全问题,因为它不允许客户端访问 CherryPy 应用程序堆栈。然而,由于限制是在套接字级别完成的,CherryPy 应用程序永远无法看到客户端连接,因此该解决方案有些不灵活。
最佳解决方案是允许客户端连接到 CherryPy 套接字并将客户端证书发送到应用程序堆栈。然后自定义 CherryPy 工具将验证应用程序堆栈内的证书并在必要时关闭连接;不幸的是,由于 CherryPy 的 pyOpenSSL 实现的结构,很难在应用程序堆栈内检索客户端证书。
当然,上述补丁只能在您自担风险的情况下使用。如果您想出更好的解决方案,请告诉我们。