2011-04-17 80 views
3

我想在Python 3上实现一个简单的XML-RPC服务器,并且我希望它使用标准的ssl库(包含在Python 2.6和Python 3.x中)通过HTTPS运行。 。Python 3中的HTTPS的XMLRPC服务器

我见过一些代码,它与OpenSSL或M2Crypto模块,但我想避免任何依赖。

我实现了一个代码应包裹SSL协议在插座:

"""Monkey patching standard xmlrpc.server.SimpleXMLRPCServer 
to run over TLS (SSL) 

Changes inspired on http://www.cs.technion.ac.il/~danken/SecureXMLRPCServer.py 
""" 
import socket 
import socketserver 
import ssl 
from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCDispatcher, SimpleXMLRPCRequestHandler 
try: 
    import fcntl 
except ImportError: 
    fcntl = None 


class SimpleXMLRPCServerTLS(SimpleXMLRPCServer): 
    def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler, 
       logRequests=True, allow_none=False, encoding=None, bind_and_activate=True): 
     """Overriding __init__ method of the SimpleXMLRPCServer 

     The method is an exact copy, except the TCPServer __init__ 
     call, which is rewritten using TLS 
     """ 
     self.logRequests = logRequests 

     SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding) 

     """This is the modified part. Original code was: 

      socketserver.TCPServer.__init__(self, addr, requestHandler, bind_and_activate) 

     which executed: 

      def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): 
       BaseServer.__init__(self, server_address, RequestHandlerClass) 
       self.socket = socket.socket(self.address_family, 
              self.socket_type) 
       if bind_and_activate: 
        self.server_bind() 
        self.server_activate() 

     """ 
     socketserver.BaseServer.__init__(self, addr, requestHandler) 
     self.socket = ssl.wrap_socket(
      socket.socket(self.address_family, self.socket_type), 
      server_side=True, 
      cert_reqs=ssl.CERT_NONE, 
      ssl_version=ssl.PROTOCOL_TLSv1, 
      ) 
     if bind_and_activate: 
      self.server_bind() 
      self.server_activate() 

     """End of modified part""" 

     # [Bug #1222790] If possible, set close-on-exec flag; if a 
     # method spawns a subprocess, the subprocess shouldn't have 
     # the listening socket open. 
     if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'): 
      flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD) 
      flags |= fcntl.FD_CLOEXEC 
      fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags) 

但由于某些原因,我不能确定,它提出这个错误:致电前

[Errno 8] _ssl.c:502: EOF occurred in violation of protocol 

远程方法。

有没有人知道会发生什么,或者对如何收集更多信息以获得线索可能是什么问题有任何想法?

非常感谢你提前!

UPDATE:

固定。代码有两个错误。首先,需要指定证书文件(也可以包含密钥)。

其次是xmlrpc.client.ServerProxy(包含在Python中)正在使用SSLv2,因此TLSv1不起作用。

工作代码为:

"""Monkey patching standard xmlrpc.server.SimpleXMLRPCServer 
to run over TLS (SSL) 

Changes inspired on http://www.cs.technion.ac.il/~danken/SecureXMLRPCServer.py 
""" 
import socket 
import socketserver 
import ssl 
from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCDispatcher, SimpleXMLRPCRequestHandler 
try: 
    import fcntl 
except ImportError: 
    fcntl = None 


class SimpleXMLRPCServerTLS(SimpleXMLRPCServer): 
    def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler, 
       logRequests=True, allow_none=False, encoding=None, bind_and_activate=True): 
     """Overriding __init__ method of the SimpleXMLRPCServer 

     The method is an exact copy, except the TCPServer __init__ 
     call, which is rewritten using TLS 
     """ 
     self.logRequests = logRequests 

     SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding) 

     """This is the modified part. Original code was: 

      socketserver.TCPServer.__init__(self, addr, requestHandler, bind_and_activate) 

     which executed: 

      def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): 
       BaseServer.__init__(self, server_address, RequestHandlerClass) 
       self.socket = socket.socket(self.address_family, 
              self.socket_type) 
       if bind_and_activate: 
        self.server_bind() 
        self.server_activate() 

     """ 
     socketserver.BaseServer.__init__(self, addr, requestHandler) 
     self.socket = ssl.wrap_socket(
      socket.socket(self.address_family, self.socket_type), 
      server_side=True, 
      certfile='cert.pem', 
      cert_reqs=ssl.CERT_NONE, 
      ssl_version=ssl.PROTOCOL_SSLv23, 
      ) 
     if bind_and_activate: 
      self.server_bind() 
      self.server_activate() 

     """End of modified part""" 

     # [Bug #1222790] If possible, set close-on-exec flag; if a 
     # method spawns a subprocess, the subprocess shouldn't have 
     # the listening socket open. 
     if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'): 
      flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD) 
      flags |= fcntl.FD_CLOEXEC 
      fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags) 
+0

确保两个地正在运行的服务器和客户端上都在和工作。 – 2011-04-17 01:02:24

+0

为什么不将ssl卸载到真正的Web服务器(apache/lighttpd)或负载均衡器? – 2011-04-17 01:02:30

+0

此代码不适用于单个主机安装,但适用于可在不需要最终用户设置http服务器的情况下分发的程序。 – 2011-04-17 01:50:48

回答

-1

移动你的Python服务器后面,如Apache,Nginx的或任何一个反向代理,让反向代理的SSL工作......这个作品比上更好,更流畅Python级别。

1

你为什么不写就像这样:

server = SimpleXMLRPCServer(...) 
... 
server.socket = ssl.wrap_socket(srv.socket, ...) 
server.serve_forever() 
+0

你节省了我的一天,非常感谢。 – 2014-02-20 15:41:28