Запрос HTTP Connect через каскадный прокси

Я создаю прокси-сервер на питоне, основанный на BaseHTTPServer. Что он делает, так это создает соединение с прокси-сервером squid, идентифицирует запрос браузера (GET, CONNECT, POST и т. д.) и добавляет к нему заголовок авторизации прокси-сервера, а затем перенаправляет этот запрос прокси-серверу squid.

Проблема в том, насколько я понимаю, когда я отправляю запрос на соединение, я должен ретранслировать весь соответствующий трафик на прокси-сервер squid. Но, как я вижу в wireshark, прокси-сервер squid не отвечает на часть рукопожатия «Client Hello», что, я думаю, связано с тем, что прокси-сервер squid не понимает двоичные данные SSL, которые я просто пересылаю ему.

Как мне обрабатывать HTTPS-запросы в этом случае?

Код более или менее похож на TinyHTTPProxy: http://www.oki-osk.jp/esc/python/proxy/


person Polymorph    schedule 15.02.2013    source источник


Ответы (1)


RFC 2817 определяет метод CONNECT. Он отличается от других HTTP-методов тем, что принимающий прокси-сервер (ваш прокси-сервер Python) направлен на установление необработанного TCP-туннеля туннеля непосредственно к целевому хосту (называемому авторитетом в РФЦ).

Прокси не может делать никаких предположений о данных, которые будут отправлены по этому туннелю; это не обязательно будет HTTP, клиент может использовать туннель для общения по любому протоколу, который ему нравится. Действительно, SSL HTTP.

У вас есть два варианта:

  • Откройте TCP-соединение непосредственно с запрошенным хостом назначения.
  • Сделайте CONNECT запрос к вашему восходящему прокси (Squid). Это в пределах спецификации:

    Может случиться так, что сам прокси-сервер может получить доступ к запрошенному исходному серверу только через другой прокси-сервер. В этом случае первый прокси ДОЛЖЕН сделать CONNECT запрос следующего прокси, запрашивая туннель к авторитету. Прокси-сервер НЕ ДОЛЖЕН отвечать каким-либо кодом состояния 2xx, если только у него не установлено прямое или туннельное соединение с центром.

    Убедитесь, что ваш запрос включает обязательный заголовок Host.

    CONNECT www.google.com:443 HTTP/1.1
    Host: www.google.com:443
    Proxy-Authorization: ...
    ​
    
person josh3736    schedule 03.03.2013
comment
Я делаю то же самое. Вот код, который я реализовал: PROXY_ADDR = ("172.16.27.25", 3128) #Squid proxy CONNECT = "CONNECT www.gooogle.com:443 HTTP/1.1\r\n" proxy_auth = "Proxy-Authorization: Basic " + str(encoded_user_pass) + "\r\n" CONNECT = CONNECT + proxy_auth + "\r\n" s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(PROXY_ADDR) s.send(CONNECT) После этого он инициирует рукопожатие, но не может получить ответ от сервера Squid (привет серверу). - person Polymorph; 04.03.2013
comment
Я не могу правильно отформатировать приведенный выше код. По сути, он подключается к прокси-серверу squid (внутренний IP-адрес) и отправляет запрос CONNECT с авторизацией прокси-сервера. (который не работает при рукопожатии) Я использовал построитель прокси в модуле urllib2, и он отлично работает с прокси-сервером squid, но я не понимаю, почему приведенный выше код не работает. - person Polymorph; 04.03.2013
comment
@Polymorph: вам не хватает заголовка Host в вашем запросе CONNECT. HTTP/1.1 требует, чтобы клиент ДОЛЖЕН включать Host заголовок во всех запросах. - person josh3736; 05.03.2013
comment
Ok. Я попытался использовать заголовок хоста в запросе HTTP/1.1. Я также пробовал с запросом HTTP/1.0. Оба они терпят неудачу в части рукопожатия. - person Polymorph; 13.03.2013