我想在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)
確保兩個地正在運行的服務器和客戶端上都在和工作。 – 2011-04-17 01:02:24
爲什麼不將ssl卸載到真正的Web服務器(apache/lighttpd)或負載均衡器? – 2011-04-17 01:02:30
此代碼不適用於單個主機安裝,但適用於可在不需要最終用戶設置http服務器的情況下分發的程序。 – 2011-04-17 01:50:48