2011-04-17 77 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