4

I am trying to create an HTTPS proxy server in python, I created the following script that works with HTTP.

#!/usr/bin/env python3
# coding=utf-8
import socket
from threading import Thread
class Proxy:
 def __init__(self, port=3000):
 self.port = port
 self.proxy = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 self.proxy.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 self.buffer_size = 4096
 def run(self):
 self.proxy.bind(("0.0.0.0", self.port))
 self.proxy.listen(100)
 print(" * Proxy server is running on port {}".format(self.port))
 while True:
 client, addr = self.proxy.accept()
 print(" => {}:{}".format(addr[0], addr[1]))
 Thread(target=self.handle_request, args=(client,)).start()
 def handle_request(self, client):
 head = self.parse_head(client.recv(self.buffer_size))
 headers = head["headers"]
 request = "{}\r\n".format(head["meta"])
 for key, value in headers.items():
 request += "{}: {}\r\n".format(key, value)
 request += "\r\n"
 if "content-length" in headers:
 while len(head["chunk"]) < int(headers["content-length"]):
 head["chunk"] += client.recv(self.buffer_size)
 request = request.encode() + head["chunk"]
 port = 80
 try:
 tmp = head["meta"].split(" ")[1].split("://")[1].split("/")[0]
 except IndexError:
 client.close()
 return
 if tmp.find(":") > -1:
 port = int(tmp.split(":")[1])
 response = self.send_to_server(headers["host"], port, request)
 client.sendall(response)
 client.close()
 def send_to_server(self, host, port, data):
 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 server.connect((socket.gethostbyname(host), port))
 server.sendall(data)
 head = self.parse_head(server.recv(4096))
 headers = head["headers"]
 response = "{}\r\n".format(head["meta"])
 for key, value in headers.items():
 response += "{}: {}\r\n".format(key, value)
 response += "\r\n"
 if "content-length" in headers:
 while len(head["chunk"]) < int(headers["content-length"]):
 head["chunk"] += server.recv(self.buffer_size)
 response = response.encode() + head["chunk"]
 server.close()
 return response
 def parse_head(self, head_request):
 nodes = head_request.split(b"\r\n\r\n")
 heads = nodes[0].split(b"\r\n")
 meta = heads.pop(0).decode("utf-8")
 data = {
 "meta": meta,
 "headers": {},
 "chunk": b""
 }
 if len(nodes) >= 2:
 data["chunk"] = nodes[1]
 for head in heads:
 pieces = head.split(b": ")
 key = pieces.pop(0).decode("utf-8")
 if key.startswith("Connection: "):
 data["headers"][key.lower()] = "close"
 else:
 data["headers"][key.lower()] = b": ".join(pieces).decode("utf-8")
 return data
if __name__ == "__main__":
 proxy = Proxy(3001)
 proxy.run()

I never worked with SSL stuff in Python, so I used the ssl module to create an HTTPS socket.

#!/usr/bin/env python3
# coding=utf-8
import socket
import ssl
from threading import Thread
class Proxy:
 def __init__(self, port=3000):
 self.port = port
 self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 self.proxy = ssl.wrap_socket(self.s, ssl_version=ssl.PROTOCOL_TLSv1, ciphers="ADH-AES256-SHA")
 self.buffer_size = 4096
 def run(self):
 self.proxy.bind(("0.0.0.0", self.port))
 self.proxy.listen(100)
 print(" * Proxy server is running on port {}".format(self.port))
 while True:
 client, addr = self.proxy.accept()
 print(" => {}:{}".format(addr[0], addr[1]))
 Thread(target=self.handle_request, args=(client,)).start()
 def handle_request(self, client):
 head = self.parse_head(client.recv(self.buffer_size))
 headers = head["headers"]
 request = "{}\r\n".format(head["meta"])
 for key, value in headers.items():
 request += "{}: {}\r\n".format(key, value)
 request += "\r\n"
 if "content-length" in headers:
 while len(head["chunk"]) < int(headers["content-length"]):
 head["chunk"] += client.recv(self.buffer_size)
 request = request.encode() + head["chunk"]
 port = 80
 try:
 tmp = head["meta"].split(" ")[1].split("://")[1].split("/")[0]
 except IndexError:
 client.close()
 return
 if tmp.find(":") > -1:
 port = int(tmp.split(":")[1])
 response = self.send_to_server(headers["host"], port, request)
 client.sendall(response)
 client.close()
 def send_to_server(self, host, port, data):
 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 server.connect((socket.gethostbyname(host), port))
 server.sendall(data)
 head = self.parse_head(server.recv(4096))
 headers = head["headers"]
 response = "{}\r\n".format(head["meta"])
 for key, value in headers.items():
 response += "{}: {}\r\n".format(key, value)
 response += "\r\n"
 if "content-length" in headers:
 while len(head["chunk"]) < int(headers["content-length"]):
 head["chunk"] += server.recv(self.buffer_size)
 response = response.encode() + head["chunk"]
 server.close()
 return response
 def parse_head(self, head_request):
 nodes = head_request.split(b"\r\n\r\n")
 heads = nodes[0].split(b"\r\n")
 meta = heads.pop(0).decode("utf-8")
 data = {
 "meta": meta,
 "headers": {},
 "chunk": b""
 }
 if len(nodes) >= 2:
 data["chunk"] = nodes[1]
 for head in heads:
 pieces = head.split(b": ")
 key = pieces.pop(0).decode("utf-8")
 if key.startswith("Connection: "):
 data["headers"][key.lower()] = "close"
 else:
 data["headers"][key.lower()] = b": ".join(pieces).decode("utf-8")
 return data
if __name__ == "__main__":
 proxy = Proxy(3001)
 proxy.run()

But I get the following error.

 * Proxy server is running on port 3001
Traceback (most recent call last):
 File ".\proxy.py", line 98, in <module>
 proxy.run()
 File ".\proxy.py", line 22, in run
 client, addr = self.proxy.accept()
 File "C:\Users\anyms\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 1355, in accept
 newsock = self.context.wrap_socket(newsock,
 File "C:\Users\anyms\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 500, in wrap_socket
 return self.sslsocket_class._create(
 File "C:\Users\anyms\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 1040, in _create
 self.do_handshake()
 File "C:\Users\anyms\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 1309, in do_handshake
 self._sslobj.do_handshake()
ssl.SSLError: [SSL: HTTPS_PROXY_REQUEST] https proxy request (_ssl.c:1108)
asked Feb 13, 2020 at 22:34

1 Answer 1

4

The problem is actually not related to SSL at all but caused by a misunderstanding of how a HTTP proxy for HTTPS works. Such a proxy is not doing SSL at all. It is instead just used to create a tunnel to the final server and the client then creates the HTTPS connection trough this tunnel, keeping the end-to-end encryption this way.

The tunnel itself is created using the HTTP CONNECT method. And this is exactly what you are getting here on your SSL socket:

 ssl.SSLError: [SSL: HTTPS_PROXY_REQUEST] https proxy request (_ssl.c:1108)
 ^^^^^^^^^^^^^^^^^^^
answered Feb 14, 2020 at 6:37
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.