2011-07-06 14 views
13

Estoy escribiendo un proxy HTTP y estoy teniendo problemas para entender algunos detalles de hacer una solicitud CONNECT sobre TLS. Para obtener una mejor imagen, estoy experimentando con Apache para observar cómo interactúa con los clientes. Esto es de mi host virtual predeterminado.¿CONECTA la solicitud a un proxy HTTP directo a través de una conexión SSL?

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> 

La conversación entre Apache y mi cliente es la siguiente.

a. el cliente se conecta al example.com:443 y envía example.com en el protocolo de enlace TLS.

b. el cliente envía una solicitud HTTP.

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

c. Apache dice HTTP/1.1 400 Bad Request. El registro de errores de Apache dice

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

Parece que Apache no se fija en el encabezado de host que no sea para ver que es allí desde HTTP/1.1 requiere. Obtengo un comportamiento fallido idéntico si el cliente envía Host: foo. Si realizo la solicitud HTTP a example.com:80 sin TLS, entonces Apache me conectará a 192.168.1.1:22.

No entiendo completamente este comportamiento. ¿Hay algún problema con la solicitud CONNECT? Parece que no puedo encontrar las partes relevantes de las RFC que explican todo esto.

+1

SNI arriba significa el nombre de host enviado en el protocolo de enlace, no el encabezado de host. Como está escrito en mi respuesta a continuación, mezclar proxies SSL y CONNECT no es típico. Parece que Apache no espera esto, ya que valida el certificado. Puedes probar 'SSLStrictSNIVHostCheck off' en Apache. – eckes

Respuesta

31

No está claro si está tratando de utilizar Apache Httpd como un servidor proxy, esto explicaría el código de estado 400 que está recibiendo. CONNECT es utilizado por el cliente y enviado al servidor proxy (posiblemente Apache Httpd, pero normalmente no), no al servidor web de destino.

CONNECT se usa entre el cliente y el servidor proxy antes de establecer la conexión TLS entre el cliente y el servidor final. El cliente (C) se conecta al proxy (P) proxy.example.com y envía esta solicitud (incluyendo la línea en blanco):

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

El proxy abre una conexión TCP con www.example.com:443 (PS) y responde al cliente con un estado 200 código, la aceptación de la solicitud:

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

Después de esto, la conexión entre el cliente y el servidor proxy (CP) se mantiene abierta. El servidor proxy retransmite todo en la conexión C-P hacia y desde P-S. El cliente actualiza su conexión activa (P-S) a una conexión SSL/TLS, iniciando un protocolo de enlace TLS en ese canal. Como todo se transmite ahora al servidor, es como si el intercambio de TLS se hubiera realizado directamente con www.example.com:443.

El proxy no desempeña ningún papel en el protocolo de enlace (y por lo tanto con el SNI). El protocolo de enlace TLS pasa de manera efectiva directamente entre el cliente y el servidor final.

Si estás escribiendo un servidor proxy, todo lo que necesita hacer para permitir que sus clientes se conecten a los servidores HTTPS se lee en la solicitud CONNECT, establezca una conexión desde el proxy al servidor final (dado en la solicitud CONNECT), envía al cliente una respuesta 200 OK y luego reenvía todo lo que lees del cliente al servidor, y viceversa.

RFC 2616 trata CONNECT como una manera de establecer un túnel sencilla (que lo es). Hay más sobre esto en RFC 2817, aunque el resto de RFC 2817 (actualizaciones a TLS dentro de una conexión HTTP no proxy) rara vez se usa.

Parece que lo que intenta hacer es tener la conexión entre el cliente (C) y el proxy (P) sobre TLS. Está bien, pero el cliente no usará CONNECT para conectarse a servidores web externos (a menos que sea una conexión a un servidor HTTPS también).

+0

1) Quería entender, ¿por qué un cliente alguna vez usaría HTTP "CONNECT", cuando puede usar SSL directamente para hablar con el servidor final? Ya sea que se trate de "CONNECT" o SSL de todos modos, atravesaría los proxies configurados. 2) ¿También en qué encabezado archivado el cliente especifica la dirección intermedia del servidor proxy en la solicitud "CONEXIÓN"? – Sandeep

3

De RFC 2616 (sección 14.23):

El campo de petición-header Host especifica el host de Internet y el puerto se solicita el número del recurso, tal como se obtiene a partir del original URI dada por el usuario o recurso de referencia (generalmente una URL HTTP, como se describe en la sección 3.2.2). El valor del campo Host DEBE representar la autoridad de nombres del servidor de origen o la puerta de enlace dada por la URL original .

Según tengo entendido, debe copiar la dirección de la línea CONNECT a la línea HOST. Con todo, la dirección del recurso es 192.168.1.1, y el hecho de que se está conectando a través de example.com no cambia nada desde el punto de vista de RFC.

+0

De acuerdo con la sección 5.2, "2. Si el URI de solicitud no es una URL absoluta, y la solicitud incluye un campo de encabezado de host, el host se determina por el valor del campo del encabezado de host." Para CONNECT, Request-URI no es unaURI absoluta (sección 5.1.2). – sigjuice

+0

@sigjuice ... De modo que 5.2 no se aplica (y ¿por qué se ha referido a él?) –

+0

Desde 5.1.2, "Request-URI =" * "| absoluteURI | abs_path | authority". CONNECT usa la forma de autoridad del Request-URI. Luego, a partir de 5.2 "El recurso exacto identificado por una solicitud de Internet se determina al examinar tanto el URI de solicitud como el campo de cabecera del host". IHMO, Apache debería usar el encabezado Host para determinar el host y no fallar con el error "el host proporcionado por SNI y el host provisto por HTTP son diferentes (ejemplo.com vs 192.168.1.1). – sigjuice

2

Es bastante raro ver el método CONNECT dentro de TLS (https). De hecho, no conozco a ningún cliente que haga eso (y me gustaría saber quién lo hace, porque creo que en realidad es una buena característica).

Normalmente, el cliente se conecta con http (plain tcp) al proxy y envía el método CONNECT (y el encabezado del host) al host: 443. Luego, el proxy realizará una conexión transparente al punto final y luego el cliente enviará el protocolo de enlace SSL.

En este escenario, los datos están protegidos ssl "de extremo a extremo".

El método CONNECT no está realmente especificado, solo está reservado en el HTTP RFC. Pero, por lo general, es bastante simple, por lo que es interoperable. El método especifica el host [: puerto]. Host: header simplemente puede ser ignorado. Algunos encabezados adicionales de autenticación de proxy pueden ser necesarios. Cuando comienza el cuerpo de la conexión, el proxy ya no tiene que pasar por el análisis (algunos lo hacen, ya que verifican un apretón de manos SSL válido).

+1

Se especifica en [RFC2817] (http://tools.ietf.org/html/rfc2817#section-5.2). – schlamar

+0

Gracias @schlamar, buena pista. – eckes

+0

BTW: Chrome admite conexiones SSL a Proxies: http://www.chromium.org/developers/design-documents/secure-web-proxy – eckes

Cuestiones relacionadas