为SocketServer添加SSL支持
我有一个基于 ThreadingTCPServer
的服务器。现在我想给这个服务器添加SSL支持。没有SSL的时候,服务器运行得很好,但一旦使用SSLv3,我就无法让客户端连接到服务器,总是抛出一个异常:Error 111 Connection Refused
。这个错误的意思是那个端口上没有SSL服务器。
我根据在Stackoverflow上找到的一个例子添加了SSL支持。以下是我的代码:
服务器:
class BeastServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
SocketServer.BaseServer.__init__(self, server_address,
RequestHandlerClass)
ctx = SSL.Context(SSL.SSLv3_METHOD)
cert = 'server.pem'
key = 'key.pem'
ctx.use_privatekey_file(key)
ctx.use_certificate_file(cert)
self.socket = SSL.Connection(ctx, socket.socket(self.address_family,
self.socket_type))
if bind_and_activate:
#self.server_bind()
#self.server_a
客户端:
class Client(object) :
def verbinden (self, ip_) :
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_sock = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_SSLv3, ca_certs='server.pem')
ssl_sock.connect((ip_, 10012))
return ssl_sock
密钥和证书文件是用OpenSSL创建的。希望有人能告诉我问题出在哪里。
谢谢你的帮助。
最好的问候,Patrick
3 个回答
1
- 安装openssl
sudo aptitude install python-openssl
- 然后使用以下的Python代码
from OpenSSL import SSL
import socket, SocketServer
class SSlSocketServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
SocketServer.BaseServer.__init__(self, server_address,
RequestHandlerClass)
ctx = SSL.Context(SSL.SSLv3_METHOD)
cert = 'cert.pem'
key = 'private_key.pem'
ctx.use_privatekey_file(key)
ctx.use_certificate_file(cert)
self.socket = SSL.Connection(ctx, socket.socket(self.address_family,
self.socket_type))
if bind_and_activate:
self.server_bind()
self.server_activate()
def shutdown_request(self,request):
request.shutdown()
class Decoder(SocketServer.StreamRequestHandler):
def setup(self):
self.connection = self.request
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
def handle(self):
try:
socket1 = self.connection
str1 = socket1.recv(4096)
print str1
except Exception, e:
print 'socket error',e
def main():
server = SSlSocketServer(('127.0.0.1', 9999), Decoder)
server.serve_forever()
if __name__ == '__main__':
main()
- 现在测试服务器
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 9999))
sslSocket = socket.ssl(s)
print repr(sslSocket.server())
print repr(sslSocket.issuer())
sslSocket.write('Hello secure socket\n')
s.close()
4
其实,标准库里的ssl功能是可以正常工作的。可能最开始的代码问题在于你没有告诉基类不要绑定和激活。下面是一个基于TCPServer的有效示例。证书和密钥文件应该放在同一个目录里。
import os
import SocketServer
class SSLTCPServer(SocketServer.TCPServer):
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
"""Constructor. May be extended, do not override."""
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass, False)
dir = os.path.dirname(__file__)
key_file = os.path.join(dir, 'server.key')
cert_file = os.path.join(dir, 'server.crt')
import ssl
self.socket = ssl.wrap_socket(self.socket, keyfile=key_file, certfile=cert_file, cert_reqs=ssl.CERT_NONE)
if bind_and_activate:
self.server_bind()
self.server_activate()
12
只使用标准库
服务器端:
from SocketServer import TCPServer, ThreadingMixIn, StreamRequestHandler
import ssl
class MySSL_TCPServer(TCPServer):
def __init__(self,
server_address,
RequestHandlerClass,
certfile,
keyfile,
ssl_version=ssl.PROTOCOL_TLSv1,
bind_and_activate=True):
TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
self.certfile = certfile
self.keyfile = keyfile
self.ssl_version = ssl_version
def get_request(self):
newsocket, fromaddr = self.socket.accept()
connstream = ssl.wrap_socket(newsocket,
server_side=True,
certfile = self.certfile,
keyfile = self.keyfile,
ssl_version = self.ssl_version)
return connstream, fromaddr
class MySSL_ThreadingTCPServer(ThreadingMixIn, MySSL_TCPServer): pass
class testHandler(StreamRequestHandler):
def handle(self):
data = self.connection.recv(4096)
self.wfile.write(data)
#test code
MySSL_ThreadingTCPServer(('127.0.0.1',5151),testHandler,"cert.pem","key.pem").serve_forever()
客户端:
import os
import socket, ssl
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ssl_sock = ssl.wrap_socket(s,
ca_certs="cert.pem",
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1)
ssl_sock.connect(('127.0.0.1',5151))
ssl_sock.send('hello ~MySSL !')
print ssl_sock.recv(4096)
ssl_sock.close()
运行得很好