ПОДКЛЮЧИТЬ запрос к HTTP-прокси-серверу через SSL-соединение? - PullRequest
14 голосов
/ 06 июля 2011

Я пишу HTTP-прокси, и у меня возникают проблемы с пониманием некоторых деталей создания запроса CONNECT по TLS. Чтобы получить лучшую картину, я экспериментирую с Apache, чтобы увидеть, как он взаимодействует с клиентами. Это из моего виртуального хоста по умолчанию.

NameVirtualHost *:443
<VirtualHost>
  ServerName example.com
  DocumentRoot htdocs/example.com  
  ProxyRequests On
  AllowConnect 22
  SSLEngine on
  SSLCertificateFile /root/ssl/example.com-startssl.pem
  SSLCertificateKeyFile /root/ssl/example.com-startssl.key
  SSLCertificateChainFile /root/ssl/sub.class1.server.ca.pem
  SSLStrictSNIVHostCheck off
</VirtualHost>

Разговор между Apache и моим клиентом идет так.

а. клиент подключается к example.com:443 и отправляет example.com при подтверждении связи TLS.

б. клиент отправляет HTTP-запрос.

CONNECT 192.168.1.1:22 HTTP/1.1
Host: example.com
Proxy-Connection: Keep-Alive

с. Апач говорит HTTP/1.1 400 Bad Request. В журнале ошибок Apache написано

Hostname example.com provided via SNI and hostname 192.168.1.1
provided via HTTP are different. 

Похоже, что Apache не смотрит на заголовок Host, кроме как на то, что он там, поскольку HTTP / 1.1 требует этого. Я получаю идентичное неудачное поведение, если клиент отправляет Host: foo. Если я сделаю HTTP-запрос к example.com:80 без TLS, то Apache соединит меня с 192.168.1.1:22.

Я не совсем понимаю это поведение. Что-то не так с запросом CONNECT? Я не могу найти соответствующие части RFC, которые объясняют все это.

Ответы [ 4 ]

35 голосов
/ 06 июля 2011

Не ясно, пытаетесь ли вы использовать Apache Httpd в качестве прокси-сервера, это объясняет код состояния 400, который вы получаете.CONNECT используется клиентом и отправляется на прокси-сервер (возможно, Apache Httpd, но обычно нет), а не на целевой веб-сервер.

CONNECT используется между клиентом и прокси-серверомперед установлением соединения TLS между клиентом и конечным сервером.Клиент (C) подключается к прокси (P) proxy.example.com и отправляет этот запрос (включая пустую строку):

C->P: CONNECT www.example.com:443 HTTP/1.1
C->P: Host: www.example.com:443
C->P:

Прокси-сервер открывает TCP-соединение для www.example.com:443 (PS) и отвечает наклиент с кодом состояния 200, принимая запрос:

P->C: 200 OK
P->C: 

После этого соединение между клиентом и прокси-сервером (CP) остается открытым.Прокси-сервер передает все по соединению CP к и от PS.Клиент обновляет свое активное (PS) соединение до соединения SSL / TLS, инициируя квитирование TLS на этом канале.Поскольку теперь все ретранслируется на сервер, это похоже на обмен TLS непосредственно с www.example.com:443.

Прокси-сервер не играет никакой роли в рукопожатии (и, следовательно, с SNI).Рукопожатие TLS эффективно происходит непосредственно между клиентом и конечным сервером.

Если вы пишете прокси-сервер, все, что вам нужно сделать, чтобы позволить вашим клиентам подключаться к HTTPS-серверам, читается в CONNECTзапросите, подключитесь от прокси к конечному серверу (указанному в запросе CONNECT), отправьте клиенту ответ 200 OK, а затем перешлите все, что вы прочитали, с сервера на сервер, и наоборот.

RFC 2616 рассматривает CONNECT как способ создания простого туннеля (который он есть).В RFC 2817 есть больше об этом, хотя остальная часть RFC 2817 (обновления до TLS в непрокси-HTTP-соединении) используется редко.

Похоже, что выПопытка сделать это имеет соединение между клиентом (C) и прокси (P) по TLS.Это нормально, но клиент не будет использовать CONNECT для подключения к внешним веб-серверам (если только это не соединение с сервером HTTPS).

3 голосов
/ 12 сентября 2013

Вы все делаете правильно. Это Apache, который все неправильно понял. Поддержка CONNECT over TLS была добавлена ​​только недавно (https://issues.apache.org/bugzilla/show_bug.cgi?id=29744), и есть еще кое-что, что нужно решить. Проблема, которую вы затрагиваете, одна из них.

3 голосов
/ 06 июля 2011

Из RFC 2616 (раздел 14.23):

В поле заголовка запроса хоста указывается хост Интернета и номер порта запрашиваемого ресурса, полученные из исходного URI, предоставленного пользователем илиссылающийся ресурс (как правило, HTTP-URL, как описано в разделе 3.2.2).Значение поля Host ДОЛЖНО представлять полномочия именования исходного сервера или шлюза, заданного исходным URL.

Насколько я понимаю, вам необходимо скопировать адрес из строки CONNECT в строку HOST.В общем, адрес ресурса - 192.168.1.1, и тот факт, что вы подключаетесь через example.com, ничего не меняет с точки зрения RFC.

2 голосов
/ 16 февраля 2013

Редко можно увидеть метод CONNECT внутри TLS (https).Я на самом деле не знаю ни одного клиента, который делает это (и мне было бы интересно узнать, кто это делает, потому что я думаю, что это на самом деле хорошая функция).

Обычно клиент соединяется с http (plain tcp)на прокси-сервер и отправляет метод CONNECT (и заголовок хоста) на хост: 443.Затем прокси-сервер установит прозрачное соединение с конечной точкой, а затем клиент отправит SSL-рукопожатие через.

В этом сценарии данные защищены ssl «конец в конец».

Метод CONNECTна самом деле не указано, оно зарезервировано только в HTTP RFC.Но, как правило, это довольно просто, поэтому он совместим.Метод указывает хост [: порт].Заголовок Host: может быть просто проигнорирован.Могут потребоваться некоторые дополнительные заголовки аутентификации прокси.Когда начинается тело соединения, прокси-сервер больше не должен выполнять синтаксический анализ (некоторые делают это, потому что проверяют правильное SSL-рукопожатие).

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