Skip to content


网络安全通讯(5)—-支持客户端验证的python web server

前面我们说道很多的场景是需要客户端验证(Client Certificate)的,而python的web server如何支持呢?
大多数的python web server都是符合WSGI标准的,也就是他们提供WSGI标准支持的功能,也就是他们几乎都不支持WSGI不支持的功能。很遗憾,客户端验证不在此列。换句话说,Cherrypy,webpy等常用的python web server都无法支持客户端验证。

我终于找到了Twisted(他怎么一下从2.5就蹦到了8.0.1)的web模块可以作为一个单独的web server。而这个web模块是包装的很底层的,使用pyopenssl,并且不是WSGI的一个实现。也就是说,他很可能是支持客户端验证的。
经过一番google,发现了支持的办法。如下:
首先我们看一下如何让Twisted支持HTTPS,他需要执行reactor.listenSSL方法,

class Hello(Resource) :
    isLeaf = True
    def render(self, request) :
        return ‘Hello, SSL’
root = server.Site(Hello())
ctxFactory = ssl.DefaultOpenSSLContextFactory(
    ‘/path/to/server.key’,
    ‘/path/to/server.crt’
    )
reactor.listenSSL(443, root, contextFactory = ctxFactory)
reactor.run()

这是最基本的支持HTTPS的方法,我们看,他需要一个contextFactory,深入到Twisted里面发现这个contextFactory是SSL进行设置。我们想要他支持客户端验证,就要从这里下手了。
DefaultOpenSSLContextFactory的cacheContext方法是对context进行的操作。我们重写这个方法。

class SSLClientCertificateFactory(ssl.DefaultOpenSSLContextFactory) :

    def __init__(self, privateKeyFileName, certificateFileName, sslmethod=SSL.SSLv23_METHOD) :
        ssl.DefaultOpenSSLContextFactory.__init__(self, privateKeyFileName, certificateFileName, sslmethod)

    def _verify(self, connection, x509, errnum, errdepth, ok):
        “”"
        print ‘_verify (ok=%d):’ % ok
        print ‘  subject:’, x509.get_subject()
        print ‘  issuer:’, x509.get_issuer()
        print ‘  errnum %s, errdepth %d’ % (errnum, errdepth)
        “”"
        return ok
   
    def cacheContext(self) :
        ssl.DefaultOpenSSLContextFactory.cacheContext(self)

        ctx = self._context
        ctx.load_verify_locations(‘/path/to/ca.crt’)
        ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, self._verify)

        self._context = ctx

我们在通过默认的contextFactory生成context之后,执行ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, self._verify),这样就加入和客户端验证,并且在self._verify函数里面我们还可以具体的验证证书的情况。
改写最上面的程序,
class Hello(Resource) :
    isLeaf = True
    def render(self, request) :
        return ‘Hello, SSL’
root = server.Site(Hello())
ctxFactory = SSLClientCertificateFactory(
    ‘/path/to/server.key’,
    ‘/path/to/server.crt’
    )
reactor.listenSSL(443, root, contextFactory = ctxFactory)
reactor.run()

好了,此时我们的python web server已经支持客户端验证了

后记:这里我有一个思考,就是为什么WSGI(暂时)不支持客户端验证?我想应该不是设计者忽视了这个问题。一般的,需要客户端验证这样的应用场景,很难只是假设一个python的web server,前面应该都有一个Apache等纯粹的服务器,那么这些验证之类的工作完全交付给Apache就足够好了,python没必要自己来处理。也许这就是原因吧。
那么,从这里我们也能看出,作为一个纯粹的网络应用组件,Twisted至少从功能上还是非常强大的。

Posted in python, 安全.

Tagged with , , .


0 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.



Some HTML is OK

or, reply to this post via trackback.