Я пытаюсь обрабатывать HTTPS-соединения из веб-браузеров в расшифрованных данных с использованием Python-сокета SSL.Я думал, что смогу сделать это как атаку «человек посередине» через мою программу прокси-сервера Python, выдав себя за , выдавая себя за HTTPS-сервер , и я уже сгенерировал свои ключи, используя OpenSSL.Однако браузер рассматривает мою программу как прокси-сервер , а не как HTTPS-сервер.Как моя программа может выдать себя за сервер HTTPS и указать свои собственные ключи для связи с браузером?
Я использую Chrome и расширение Chrome SwitchySharp для пересылки запросов на другой локальный порт (HTTP на 127.0.0.1: 8080 и HTTPS до 127.0.0.1:8081).Он хорошо работает для HTTP-запросов, но не работает для HTTPS.
Общие сведения
При обработке HTTPS с прокси-сервером браузер сначала отправляет запрос CONNECT на прокси:
CONNECT xxx.xxx:443 HTTP/1.1
Host: xxx.xxx:443
Proxy-Connection: keep-alive
(some other headers)
и прокси-сервер создает туннель для целевого сервера, а затем браузер отправляет зашифрованные данные через этот туннель.Поэтому прокси-сервер никогда не получает расшифрованные данные.
Чтобы получить расшифрованные данные, я пробовал два способа.
Сначала я попытался ssl.wrap_socket()
:
import socket
import ssl
import thread
def handle(conn):
request = conn.recv(4096)
print request
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 8081))
sock.listen(10)
sock = ssl.wrap_socket(sock, 'pkey.pem', 'cert.pem', True)
while True:
conn, addr = sock.accept()
thread.start_new_thread(handle, (conn,))
Но я получил следующую ошибку:
Traceback (most recent call last):
File "https.py", line 12, in <module>
conn, addr = sock.accept()
File "C:\Python27\lib\ssl.py", line 898, in accept
server_side=True)
File "C:\Python27\lib\ssl.py", line 369, in wrap_socket
_context=self)
File "C:\Python27\lib\ssl.py", line 617, in __init__
self.do_handshake()
File "C:\Python27\lib\ssl.py", line 846, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: HTTPS_PROXY_REQUEST] https proxy request (_ssl.c:726)
Причина этой ошибки в том, что запрос CONNECT не зашифрован, поэтому ssl не может его обработать .Я понятия не имею, как избавиться от этой ошибки.
Затем я попробовал следующий код:
import socket
import thread
def handler(conn, tunn):
while True:
data = conn.recv(40960)
if data:
tunn.sendall(data)
else:
break
def handle(conn):
request = conn.recv(40960)
print request
i = request.find(' ') + 1
j = request.find(' ', i)
host, port = request[i : j].split(':')
port = int(port)
tunn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tunn.connect((host, port))
conn.sendall('HTTP/1.1 200 Connection Established\r\n\r\n')
thread.start_new_thread(handler, (conn, tunn))
thread.start_new_thread(handler, (tunn, conn))
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 8081))
sock.listen(10)
while True:
conn, addr = sock.accept()
thread.start_new_thread(handle, (conn,))
Он работал (без модуля ssl), но Я могу 'Я не могу указать свои собственные ключи и, следовательно, не могу получить расшифрованные данные.
Кажется, что моя программа должна притвориться сервером HTTPS, чтобы "напрямую" взаимодействовать с браузером, поэтому я могу указать свой собственныйключ и получить расшифрованные данные.Но я действительно понятия не имею, как притвориться сервером HTTPS и указать свои собственные ключи.
Кто-нибудь может мне помочь?Заранее спасибо.
UPD : я наконец-то решил эту проблему с помощью модуля ssl.
Я ошибся --- Я думал, что после установления соединения браузеротправляет зашифрованные данные .Но это не так.На самом деле эти нечитаемые данные - это просто рукопожатие SSL .Так что мне нужно просто использовать ssl.wrap_socket()
после установления соединения.Кроме того, мне нужно дополнительно вызвать do_handshake () из ssl-wrapped сокета.
import socket
import ssl
import thread
def handle(tid, conn):
request = conn.recv(40960)
i = request.find(' ') + 1
j = request.find(' ', i)
if request[i : j].find(':') != -1:
host, port = request[i : j].split(':')
else:
host, port = request[i : j], 80
port = int(port)
tunn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tunn.connect((host, port))
conn.sendall('HTTP/1.1 200 Connection Established\r\n\r\n')
conn_s = ssl.wrap_socket(conn, keyfile = 'cert/userkey.pem', certfile = 'cert/usercert.pem', server_side = True, do_handshake_on_connect = False)
conn_s.do_handshake()
data = conn_s.recv(40960)
print data
conn_s.sendall('HTTP/1.1 200 OK\r\n\r\n<h1>Hello, world!</h1>')
conn_s.close()
tunn.close()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 8081))
sock.listen(10)
buf = {}
while True:
conn, addr = sock.accept()
thread.start_new_thread(handle, (conn,))
В любом случае, он не претендует на то, чтобы быть HTTPS-сервером - он все еще ведет себя как прокси-сервер.Я просто неправильно понял эти нечитаемые данные.
Спасибо тем, кто помог мне в комментариях.