Как прокси-сервер Python (использующий сокет SSL) может выдать себя за HTTPS-сервер и указать мои собственные ключи для получения расшифрованных данных? - PullRequest
0 голосов
/ 29 января 2019

Я пытаюсь обрабатывать 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-сервером - он все еще ведет себя как прокси-сервер.Я просто неправильно понял эти нечитаемые данные.

Спасибо тем, кто помог мне в комментариях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...