2013-03-06 7 views
0

У меня возникает следующая ситуация: Я вынужден использовать прокси-сервер HTTP для подключения к серверу HTTPS. По нескольким причинам мне нужен доступ к необработанным данным (до шифрования), поэтому я использую библиотеку сокетов вместо одной из конкретных HTTP-библиотек. Таким образом, я сначала подключаю TCP-сокет к прокси-серверу HTTP и выдаю команду connect.Отправка данных SSL по прокси-соединению TCP в Python

На данный момент HTTP-прокси принимает соединение и, по-видимому, перенаправляет все дополнительные данные на целевой сервер. Однако, если сейчас я пытаюсь переключиться на SSL, я получаю

error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol

, указывающий, что разъем пытался рукопожатия с HTTP-прокси, а не с целью HTTPS.

Вот код, который я до сих пор: импорт гнездо

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect(('proxy',9502)) 
s.send("""CONNECT en.wikipedia.org:443 HTTP/1.1 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:15.0) Gecko/20100101 Firefox/15.0.1 
Proxy-Connection: keep-alive 
Host: en.wikipedia.org 

""") 

print s.recv(1000) 

ssl = socket.ssl(s, None, None) 
ssl.connect(("en.wikipedia.org",443)) 

Что бы правильный путь, чтобы открыть SSL сокет к целевому серверу после подключения к HTTP прокси-сервер?

+1

Использование имени переменной, которое также является именем модуля, используемого вами ('ssl'), является ужасной идеей. – Bruno

ответ

1

(Обратите внимание, что, в общем, было бы проще использовать существующую библиотеку HTTPS, таких как PyCurl, вместо реализации все это самостоятельно.)

Во-первых, не называйте вашу переменную ssl. Это имя уже используется модулем ssl, поэтому вы не хотите его скрывать.

Во-вторых, не используйте connect во второй раз. Вы уже подключены, то, что вам нужно, это обернуть сокет. Поскольку Python не выполняет проверку сертификата по умолчанию, вам необходимо проверить удаленный сертификат и проверить имя хоста.

Вот этапы:

  • Создать свой обычный текстовый соединение и использовать CONNECT как вы делаете в первые несколько строк.
  • Прочтите полученный HTTP-запрос и убедитесь, что вы получили код состояния 200. (Вам нужно будет прочитать заголовок за строкой).
  • Используйте ssl_s = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLS1, ca_certs='/path/to/cabundle.pem'), чтобы обернуть розетку. Затем проверьте имя хоста. Стоит прочитать this answer: метод connect и что он делает после упаковки сокета.
  • Затем используйте ssl_s, как если бы это был ваш обычный разъем. Не вызывайте connect еще раз.