使用 Python 创建一个支持 SSL 和纯文本连接的智能 Socket

在编写一个使用 Python 的 HTTPServer 和 BaseHTTPRequest 的应用程序时,为了保护用户发送的敏感数据,作者希望实现一个 SOCKS 服务器。但是,应用程序计划在非标准端口上运行,因此需要一个支持 SSL 和纯文本连接的 Socket。作者研究了 HTTPServer 使用 SSL 的方法,但发现无法直接创建能够同时处理 SSL 和纯文本连接的 Socket。

2、解决方案

解决方案一:

一位答主提供了一种使用多线程和两个后端服务器(HTTPS 和 HTTP)的方法。前端服务器监听端口 4443 并根据收到的数据类型决定是与 HTTPS 后端服务器还是 HTTP 后端服务器通信。该方案使用字典来跟踪前端服务器和后端服务器之间的源端口号以及客户端 IP 地址,以便后端服务器能够知道客户端的 IP 地址。

解决方案二:

另一位答主提供了一种使用辅助类 SmartServerSocket 的方法。该类在 accept() 时窥探收到的数据,然后返回一个包装的或裸的 Socket。如果收到的第一个字节是 “\x16”,则返回一个使用 SSL 包装的 Socket,否则返回一个裸的 Socket。这样,应用程序只需要创建一个 HTTPServer 对象并将其 Socket 属性设置为 SmartServerSocket 的实例,就可以同时支持 SSL 和纯文本连接。

代码示例:

# 使用多线程和两个后端服务器(HTTPS 和 HTTP)的方法

FRONTEND_PORT = 4443
BACKEND_PORT_SSL = 44431
BACKEND_PORT_HTTP = 44432
HOST = 'localhost'

httpd_ssl = BaseHTTPServer.HTTPServer((HOST, BACKEND_PORT_SSL), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd_ssl.socket = ssl.wrap_socket (httpd_ssl.socket, certfile='key.pem', server_side=True)

httpd_direct = BaseHTTPServer.HTTPServer((HOST, BACKEND_PORT_HTTP), SimpleHTTPServer.SimpleHTTPRequestHandler)

def serve_forever(http_server):
    http_server.serve_forever()

def categorize(sock, addr):
    data = sock.recv(1)
    if data == '\x16':
        port = BACKEND_PORT_SSL
    else:
        port = BACKEND_PORT_HTTP
    other_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    other_sock.connect((HOST, port))
    other_sock.send(data)
    inp = [sock, other_sock]
    select_timeout = 1.0
    try:
        while 1:
            r,w,x = select.select(inp,[],[],select_timeout)
            if not r:
                continue
            for s in r:
                o_s = inp[1] if inp[0]==s else inp[0]
                buf = s.recv(4096)
                if not buf:
                    raise socket.error
                o_s.send(buf)
    except socket.error:
        pass
    finally:
        for s in inp:
            s.close()

threading.Thread(target=serve_forever, args=(httpd_ssl,)).start()
threading.Thread(target=serve_forever, args=(httpd_direct,)).start()

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, FRONTEND_PORT))
sock.listen(10)

while True:
    conn, addr = sock.accept()
    threading.Thread(target=categorize, args=(conn, addr)).start()



# 使用 SmartServerSocket 类的方法

class SmartServerSocket:
    def __init__( self, sock ):
        self.sock = sock
        # delegate methods as needed
        _delegate_methods = [ "fileno" ]
        for method in _delegate_methods:
            setattr( self, method, getattr( sock, method ) )
    def accept( self ):
        (conn, addr) = self.sock.accept()
        if conn.recv( 1, socket.MSG_PEEK ) == "\x16":
            return (ssl.wrap_socket( conn, certfile='path/to/localhost.pem', server_side=True ), addr)
        else:
            return (conn, addr)

httpd = BaseHTTPServer.HTTPServer( ('localhost', 4443), SimpleHTTPServer.SimpleHTTPRequestHandler )
httpd.socket = SmartServerSocket( httpd.socket )
httpd.serve_forever()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值