使用 SocketServer.TCPServer 通过 SSL 建立 TCP 服务

101 阅读1分钟

想要向一个现有的基于 SocketServer.TCPServer 类的 TCP 服务器添加 SSL 支持。在该服务器的 TCPServer 类的默认构造函数中添加了 ssl.wrap_socket() 调用后,启动服务器时未出现错误。然而,修改了简单的测试客户端以支持 SSL 并连接到服务器后,connect 调用会阻塞。

image.png

2、解决方案

第一个答案中给出了两种解决方法:

  1. 在接受连接时对套接字进行封装,而不是在绑定之后。这可以通过在 MyTCPServer 类中重写 get_request() 方法来实现。

  2. 提前封装套接字,但推迟与客户端握手,直到接受连接。这可以通过在 MyTCPServer 类中重写 server_bind() 和 get_request() 方法来实现。

第二个答案中给出了另一种解决方案,其中使用了 OpenSSL 包来构建 SSL 上下文并使用 SSL.Connection 类封装套接字。

以下列出了上述提到的两个解决方案的代码示例:

解决方案 1:

class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    def get_request(self):
    http://www.jshk.com.cn/mb/reg.asp?kefu=xiaoding;//爬虫IP免费获取;
        (socket, addr) = SocketServer.TCPServer.get_request(self)
        return (ssl.wrap_socket(socket, server_side=True, certfile="cert.pem"),
                addr)


class MyStreamRequestHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        # Handle the request using the encrypted socket
        pass
class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    def server_bind(self):
        SocketServer.TCPServer.server_bind(self)
        self.socket = ssl.wrap_socket(
            self.socket, server_side=True, certfile="cert.pem",
            do_handshake_on_connect=False)

    def get_request(self):
        (socket, addr) = SocketServer.TCPServer.get_request(self)
        socket.do_handshake()
        return (socket, addr)


class MyStreamRequestHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        # Handle the request using the encrypted socket
        pass

解决方案 2:

import ssl
import socket

class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
        SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass)
        ctx = ssl.SSLContext(ssl.SSLv23_METHOD)
        cert = 'cert.pem'
        ctx.use_privatekey_file(cert)
        ctx.use_certificate_file(cert)
        self.socket = ssl.SSLSocket(ctx, socket.socket(self.address_family,
                                                        self.socket_type))
        if bind_and_activate:
            self.server_bind()
            self.server_activate()


class MyStreamRequestHandler(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):
        # Handle the request using the encrypted socket
        pass

希望这些解决方案对您使用 SSL 支持的 TCP 服务器有所帮助。