【问题标题】:Twisted listenSSL virtualhosts扭曲的listenSSL虚拟主机
【发布时间】:2012-08-22 08:41:55
【问题描述】:

目前使用一个非常简单的 Twisted NameVirtualHost 和一些 JSON 配置文件在一个 Site 对象中提供真正的基本内容。 Twisted 服务的资源都是烧瓶中内置的 WSGI 对象。

我想知道如何用SSLContext 包装到这些域的连接,因为reactor.listenSSL 只需要一个上下文,如何为每个域/子域赋予它自己的 crt 并不明显/密钥对。有没有办法为每个不需要代理的域设置带有 ssl 的命名虚拟主机?我找不到任何将NameVirtualHost 与 SSL 一起使用的 Twisted 示例,而我唯一能做的事情就是在只有一个域上下文的情况下挂上侦听端口 443 的反应器?

我想知道是否有人尝试过这个?

我的简单服务器没有任何 SSL 处理:

https://github.com/DeaconDesperado/twsrv/blob/master/service.py

【问题讨论】:

标签: ssl twisted twisted.web


【解决方案1】:

现在有一个 txsni 项目负责根据请求查找正确的证书。 https://github.com/glyph/txsni

【讨论】:

    【解决方案2】:

    只是为了给这个添加一些闭包,为了将来的搜索,这里是来自打印 SNI 的示例中的 echo 服务器的示例代码:

    from twisted.internet import ssl, reactor
    from twisted.internet.protocol import Factory, Protocol
    
    class Echo(Protocol):
        def dataReceived(self, data):
            self.transport.write(data)
    
    def pick_cert(connection):
        print('Received SNI: ', connection.get_servername())
    
    if __name__ == '__main__':
        factory = Factory()
        factory.protocol = Echo
    
        with open("keys/ca.pem") as certAuthCertFile:
            certAuthCert = ssl.Certificate.loadPEM(certAuthCertFile.read())
    
        with open("keys/server.key") as keyFile:
            with open("keys/server.crt") as certFile:
                serverCert = ssl.PrivateCertificate.loadPEM(
                    keyFile.read() + certFile.read())
    
        contextFactory = serverCert.options(certAuthCert)
    
        ctx = contextFactory.getContext()
        ctx.set_tlsext_servername_callback(pick_cert)
    
        reactor.listenSSL(8000, factory, contextFactory)
        reactor.run()
    

    而且因为让 OpenSSL 工作总是很棘手,这里是您可以用来连接它的 OpenSSL 语句:

    openssl s_client -connect localhost:8000 -servername hello_world -cert keys/client.crt -key keys/client.key
    

    针对 pyOpenSSL==0.13 运行上面的 python 代码,然后运行上面的 s_client 命令,将把它打印到屏幕上:

    ('Received SNI: ', 'hello_world')
    

    【讨论】:

      【解决方案3】:

      TLS(取代 SSL 的现代协议的名称)仅在最近才支持您正在寻找的功能。该功能称为Server Name Indication(或SNI)。现代平台上的现代浏览器支持它,但一些较旧但仍被广泛使用的平台不支持(有关支持的浏览器列表,请参阅维基百科页面)。

      Twisted 对此没有特定的内置支持。但是,它不需要任何东西。 Twisted 的 SSL 支持所基于的 pyOpenSSL 确实支持 SNI。

      set_tlsext_servername_callback pyOpenSSL API 为您提供了构建所需行为的基本机制。这使您可以定义一个回调,该回调可以访问客户端请求的服务器名称。此时,您可以指定要用于连接的密钥/证书对。您可以在 pyOpenSSL 的示例目录中找到 an example demonstrating the use of this API

      以下是该示例的摘录,为您提供要点:

      def pick_certificate(connection):
          try:
              key, cert = certificates[connection.get_servername()]
          except KeyError:
              pass
          else:
              new_context = Context(TLSv1_METHOD)
              new_context.use_privatekey(key)
              new_context.use_certificate(cert)
              connection.set_context(new_context)
      
      server_context = Context(TLSv1_METHOD)
      server_context.set_tlsext_servername_callback(pick_certificate)
      

      您可以将此方法合并到自定义上下文工厂中,然后将该上下文工厂提供给listenSSL 调用。

      【讨论】:

      • 不确定我是否正确使用了您的建议...我在 PyOpenSSL 文档中找不到示例。这是我在代码中修改的内容:github.com/DeaconDesperado/twsrv/blob/ssl/service.py 出于某种原因,尽管 virtualenv 安装了 .13,但我的任何导入扭曲的脚本都使用版本 .12 的 OpenSSL。此版本使用set_tlsext_servername_callback 引发属性错误
      • 你必须弄清楚如何让你的环境使用 pyOpenSSL 0.13。该功能在 0.12 中不可用。
      • 我现在有 0.13 工作,但我仍然不知道在哪里挂钩该回调。扭曲的文档说 ssl 工厂的 getContext 方法应该返回一个 Context 对象,但这不是 set_tlsext_servername_callback 的钩子的用途吗?
      • SNI 通过用新上下文替换原始上下文来工作。第一个上下文是具有服务器名称回调的上下文。第二个上下文是具有您要使用的密钥/证书的上下文。如果您没有由 getContext 返回的第一个 Context,则没有什么可以告诉 OpenSSL 您希望在从客户端接收到服务器名称时调用您的回调。
      • 但是你在什么时候挂钩set_tlsext_servername_callback?不在 SSL 工厂的 getContext 方法中,对吧?除非我弄错了,否则每个请求都会重复它。 getContext 方法没有收到连接实例,那么我怎样才能让它为每个请求进行 sni 查找呢?
      猜你喜欢
      • 2022-01-07
      • 2010-10-07
      • 1970-01-01
      • 2014-02-22
      • 2021-08-20
      • 2014-11-04
      • 1970-01-01
      • 2019-07-03
      • 1970-01-01
      相关资源
      最近更新 更多