Encrypting Connection To My HTTP Proxy In Python

- 1 answer

Basically, I'm trying to setup an encrypted proxy with sockets in python. currently I'm able to make connection by sending an HTTP CONNECT from my client to the proxy server, and receiving a 'CODE 200 OK' response. The proxy server acts as a tunnel from the client to the desired domain/Ip and works perfectly fine.

The problem is: How can I manage to encrypt the whole connection? the first HTTP Connect isn't encrypted and can be easily sniffed and seen.

Here's the server code:

import socket, threading
MAX_BUFFER = 64 * 512
class ClientThread(threading.Thread):

    def __init__(self, clientAddress, clientsocket):
        self.browser = clientsocket

    def run(self): 
        while True:
            request = self.browser.recv(MAX_BUFFER)
            # parse the first line
            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            webserver, port = self.get_domain_port(request)
            if 'CONNECT' in request:
            # Connect to port 443
                print request
                    # If successful, send 200 code response
                    client.connect(( webserver, port ))
                    reply = "HTTP/1.0 200 Connection established\r\n"
                    reply += "Proxy-agent: FIMA\r\n"
                    reply += "\r\n"
                    self.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
                # Indiscriminately forward bytes
                while True:
                        request = self.browser.recv(MAX_BUFFER)
                        client.sendall( request )

                    except socket.error as err:
                        reply = client.recv(MAX_BUFFER)
                        self.browser.sendall( reply )
                    except socket.error as err:

        print ("Client at ", self.ssl_browser , " disconnected...")

    def get_domain_port(self, request):
        first_line = request.split('\n')[0]

        # get url
        url = first_line.split(' ')[1]

        http_pos = url.find("://") # find pos of ://
        if (http_pos==-1):
            temp = url
            temp = url[(http_pos+3):] # get the rest of url

        port_pos = temp.find(":") # find the port pos (if any)

        # find end of web server
        webserver_pos = temp.find("/")
        if webserver_pos == -1:
            webserver_pos = len(temp)

        webserver = ""
        port = -1
        if (port_pos==-1 or webserver_pos < port_pos): 

            # default port 
            port = 80 
            webserver = temp[:webserver_pos] 

        else: # specific port 
            port = int((temp[(port_pos+1):])[:webserver_pos-port_pos-1])
            webserver = temp[:port_pos] 

        return webserver, port

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('', 80))

    while True:
        conn, addr = sock.accept()
        newthread = ClientThread(addr, conn)
        newthread.daemon = True

if __name__ == "__main__":


The normal way is to have a HTTP proxy and use plain CONNECT method to create a tunnel. This tunnel is then used for end-to-end encrypted HTTPS between client and server.

It is possible though to also encrypt the connection between client and proxy, which for the HTTPS tunnel then results in encryption between client and proxy on top of encryption between client and server. To do this you need create not a plain socket, but a SSL socket with certificate etc - there are lots of documentation and examples on how to do this.

Note that this setup is not universally supported. Some browsers like Firefox do support this while others don't. Non-browser clients commonly don't support such a setup.