Python HTTPS 代理隧道

9 投票
1 回答
11469 浏览
提问于 2025-04-18 09:46

我正在尝试用Python制作一个HTTP代理。目前除了HTTPS以外的部分都已经完成,所以接下来我需要实现CONNECT方法。

在进行HTTPS隧道连接时,我对需要发生的事件顺序有点困惑。根据我的理解,当我连接到谷歌时,应该是这样的:

浏览器 -> 代理

CONNECT www.google.co.uk:443 HTTP/1.1\r\n\r\n

然后,代理应该和google.co.uk建立一个安全连接,并通过发送以下内容来确认:

代理 -> 浏览器

HTTP/1.1 200 Connection established\r\n\r\n

在这个时候,我希望浏览器能够继续它最开始要做的事情,但我要么什么都没有收到,要么收到一串我无法解码的字节。我已经阅读了关于SSL隧道的各种资料,我认为我应该把浏览器和服务器之间的所有字节都转发过去,反之亦然。但是,当我这样做时,我得到了:

HTTP/1.0 400 Bad Request\r\n...\r\n

一旦我发送了200代码,接下来我应该做什么呢?

这是我CONNECT方法的代码片段:

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
if headers["Method"] == "CONNECT":
    client = ssl.wrap_socket(client)
    
    try:
        client.connect(( headers["Host"], headers["Port"] ))
        reply = "HTTP/1.0 200 Connection established\r\n"
        reply += "Proxy-agent: Pyx\r\n"
        reply += "\r\n"
        browser.sendall( reply.encode() )
    except socket.error as err:
        print(err)
        break
    
    while True:
        now not sure

1 个回答

7

在找到这个与相关问题的答案后:HTTPS代理实现(SSLStream)

我意识到,连接到目标服务器(在这个例子中是google.co.uk)的443端口时,最开始的连接不应该是加密的。因此,我删除了

client = ssl.wrap_socket(client)

这一行,以便继续使用明文隧道,而不是ssl。一旦

HTTP/1.1 200 Connection established\r\n\r\n

消息发送出去,浏览器和最终服务器就会通过代理建立自己的ssl连接,所以代理不需要处理任何与实际https连接相关的事情。

修改后的代码(包括字节转发):

# If we receive a CONNECT request
if headers["Method"] == "CONNECT":
    # Connect to port 443
    try:
        # If successful, send 200 code response
        client.connect(( headers["Host"], headers["Port"] ))
        reply = "HTTP/1.0 200 Connection established\r\n"
        reply += "Proxy-agent: Pyx\r\n"
        reply += "\r\n"
        browser.sendall( reply.encode() )
    except socket.error as err:
        # If the connection could not be established, exit
        # Should properly handle the exit with http error code here
        print(err)
        break
    
    # Indiscriminately forward bytes
    browser.setblocking(0)
    client.setblocking(0)
    while True:
        try:
            request = browser.recv(1024)
            client.sendall( request )
        except socket.error as err:
            pass
        try:
            reply = client.recv(1024)
            browser.sendall( reply )
        except socket.error as err:
            pass

参考资料:

HTTPS代理实现(SSLStream)

https://datatracker.ietf.org/doc/html/draft-luotonen-ssl-tunneling-03

http://www.ietf.org/rfc/rfc2817.txt

撰写回答