Conexiones HTTPS a través de servidores proxy

Respuestas:

66

TLS / SSL (La S en HTTPS) garantiza que no hay espías entre usted y el servidor con el que está contactando, es decir, no hay proxies. Normalmente, se utiliza CONNECTpara abrir una conexión TCP a través del proxy. En este caso, el proxy no podrá almacenar en caché, leer o modificar ninguna solicitud / respuesta y, por lo tanto, será bastante inútil.

Si desea que el proxy pueda leer información, puede tomar el siguiente enfoque:

  1. El cliente inicia la sesión HTTPS
  2. Proxy intercepta de forma transparente la conexión y devuelve un (posiblemente débil) certificado generado ad-hoc K una , firmado por una autoridad de certificación que se incondicionalmente de confianza para el cliente.
  3. El proxy inicia la sesión HTTPS para apuntar
  4. El proxy verifica la integridad del certificado SSL; muestra error si el certificado no es válido.
  5. Proxy transmite contenido, lo descifra y lo vuelve a cifrar con K a
  6. El cliente muestra cosas

Un ejemplo es el salto SSL de Squid . Del mismo modo, el eructo se puede configurar para hacer esto. Esto también ha sido utilizado en un contexto menos benigno por un ISP egipcio .

Tenga en cuenta que los sitios web y los navegadores modernos pueden emplear HPKP o pines de certificado integrados que anulan este enfoque.

Phihag
fuente
13
Esto podría funcionar en principio, pero esa no es la forma en que los navegadores se comunican con los proxies HTTP para las solicitudes HTTPS. La forma en que se describe aquí implica que el servidor proxy es efectivamente un Man-In-The-Middle (por lo que debería ser confiable en consecuencia).
Bruno
5
Squid hace esto. Se llama SSL Bump .
Adam Mackler
3
No funcionará sin muchas alertas para el usuario final. "incondicionalmente confiado por el cliente" - no existe tal cosa. Incluso si el certificado es perfecto-AAA +++, todavía muestra un dominio diferente que no coincide con lo que solicitó el usuario final, lo que hará que cualquier navegador en su sano juicio (no significa IE aquí ...) salte arriba y abajo gritando. Por supuesto, es posible usar wget con parámetros que deshabilitan las comprobaciones SSL, pero ¿adivinen qué? esta conexión ya no se puede llamar "SSL" después de que se deshabiliten sus controles de seguridad básicos.
Van Jone
1
@Van Jone se Unconditionally trustedrefiere a un certificado de CA. Los certificados de CA no tienen dominios. He modificado la respuesta con dos ejemplos en los que esto funciona / funcionó en la práctica sin ninguna alerta para el usuario.
phihag
6
Mi respuesta se basa en lo que usted llama una "CA falsa". El certificado de la CA es de confianza incondicional, ya sea porque el usuario (o el software en su computadora, por ejemplo, la configuración empresarial o el malware) lo configuró de esa manera, o porque la CA se obtuvo de una de las CA en las que confían los principales navegadores, como en el caso MCS. El proxy genera un nuevo certificado válido para cada dominio que solicita el cliente, por lo que sin las instalaciones anti-MITM mencionadas al final de la respuesta, el cliente no se dará cuenta.
phihag
22

La respuesta corta es: es posible y se puede hacer con un proxy HTTP especial o un proxy SOCKS.

En primer lugar, HTTPS usa SSL / TLS que, por diseño, garantiza la seguridad de un extremo a otro al establecer un canal de comunicación seguro sobre uno inseguro. Si el proxy HTTP puede ver el contenido, entonces es un interlocutor intermedio y esto anula el objetivo de SSL / TLS. Por lo tanto, debe haber algunos trucos si queremos hacer un proxy a través de un proxy HTTP simple.

El truco es que convertimos un proxy HTTP en un proxy TCP con un comando especial llamado CONNECT. No todos los proxies HTTP admiten esta función, pero muchos lo hacen ahora. El proxy TCP no puede ver el contenido HTTP que se transfiere en texto sin cifrar, pero eso no afecta su capacidad para reenviar paquetes de un lado a otro. De esta manera, el cliente y el servidor pueden comunicarse entre sí con la ayuda del proxy. Esta es la forma segura de transferir datos HTTPS.

También existe una forma insegura de hacerlo, en la que el proxy HTTP se convierte en un intermediario. Recibe la conexión iniciada por el cliente y luego inicia otra conexión con el servidor real. En un SSL / TLS bien implementado, se notificará al cliente que el proxy no es el servidor real. Entonces, el cliente debe confiar en el proxy ignorando la advertencia para que las cosas funcionen. Después de eso, el proxy simplemente descifra los datos de una conexión, los vuelve a cifrar y los alimenta a la otra.

Finalmente, ciertamente podemos proxy HTTPS a través de un proxy SOCKS , porque el proxy SOCKS funciona en un nivel más bajo. Puede pensar que un proxy SOCKS es un proxy TCP y UDP.

Cyker
fuente
¿Usar CONNECT causaría advertencias de seguridad como se menciona en stackoverflow.com/a/3118759/632951 ?
Pacerier
@Pacerier No lo creo. En el modo CONNECT, el proxy trabaja en la capa de transporte.
Cyker
Entonces, por el método CONNECT, ¿los datos https del cliente no se pasan al nivel de aplicación del proxy intermediario? ¿Y solo se evaluó a nivel TCP de proxy y se transmitió directamente al servidor remoto ?
zzinny
15

Por lo que puedo recordar, debe utilizar una consulta HTTP CONNECT en el proxy. esto convertirá la conexión de la solicitud en un túnel TCP / IP transparente.

por lo que necesita saber si el servidor proxy que utiliza es compatible con este protocolo.

chburd
fuente
3
De hecho, los clientes usan el verbo CONNECT para usar https: // URI a través de servidores proxy HTTP. En este caso, la conexión se tuneliza a través del proxy, por lo que la verificación del certificado se realiza como de costumbre, como si el cliente estuviera hablando directamente con el servidor final.
Bruno
1
@chburd, pero, ¿los proxies suelen admitir HTTP CONNECT?
Pacerier
9

Si todavía le interesa, aquí hay una respuesta a una pregunta similar: Convierta el proxy HTTP en proxy HTTPS en Twisted

Para responder a la segunda parte de la pregunta:

Si es así, ¿qué tipo de servidor proxy permite esto?

De fábrica, la mayoría de los servidores proxy se configurarán para permitir conexiones HTTPS solo al puerto 443, por lo que los URI https con puertos personalizados no funcionarían. Esto generalmente se puede configurar, según el servidor proxy. Squid y TinyProxy lo admiten, por ejemplo.

Bruno
fuente
5

Aquí está mi código Java completo que admite solicitudes HTTP y HTTPS utilizando el proxy SOCKS.

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;

/**
 * How to send a HTTP or HTTPS request via SOCKS proxy.
 */
public class ClientExecuteSOCKS {

    public static void main(String[] args) throws Exception {
        Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create()
            .register("http", new MyHTTPConnectionSocketFactory())
            .register("https", new MyHTTPSConnectionSocketFactory(SSLContexts.createSystemDefault
                ()))
            .build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);
        try (CloseableHttpClient httpclient = HttpClients.custom()
            .setConnectionManager(cm)
            .build()) {
            InetSocketAddress socksaddr = new InetSocketAddress("mysockshost", 1234);
            HttpClientContext context = HttpClientContext.create();
            context.setAttribute("socks.address", socksaddr);

            HttpHost target = new HttpHost("www.example.com/", 80, "http");
            HttpGet request = new HttpGet("/");

            System.out.println("Executing request " + request + " to " + target + " via SOCKS " +
                "proxy " + socksaddr);
            try (CloseableHttpResponse response = httpclient.execute(target, request, context)) {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                System.out.println(EntityUtils.toString(response.getEntity(), StandardCharsets
                    .UTF_8));
            }
        }
    }

    static class MyHTTPConnectionSocketFactory extends PlainConnectionSocketFactory {
        @Override
        public Socket createSocket(final HttpContext context) throws IOException {
            InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
            Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
            return new Socket(proxy);
        }
    }

    static class MyHTTPSConnectionSocketFactory extends SSLConnectionSocketFactory {
        public MyHTTPSConnectionSocketFactory(final SSLContext sslContext) {
            super(sslContext);
        }

        @Override
        public Socket createSocket(final HttpContext context) throws IOException {
            InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
            Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
            return new Socket(proxy);
        }
    }
}
soulmachine
fuente
3

Puede lograr esto utilizando técnicas de intermediario con generación dinámica de SSL. Eche un vistazo a mitmproxy : es un proxy MITM compatible con SSL y basado en Python.

Zorayr
fuente
3

tunelización HTTPS a través de SSH (versión linux):

1) turn off using 443 on localhost
2) start tunneling as root: ssh -N login@proxy_server -L 443:target_ip:443
3) adding 127.0.0.1 target_domain.com to /etc/hosts

todo lo que haces en localhost. luego:

target_domain.com is accessible from localhost browser.
Sławomir Lenart
fuente
1

Había intentado

  • empezar a hacer túneles: ssh -N -D 12345 login@proxy_server
  • Configurar el proxy en la configuración de Firefox como localhost:12345
    • y marcando "usar este proxy para todos los protocolos"

pero esto resultó en el error "Conexión insegura" cada vez que intentaba conectarme a un sitio web https.

La solución fue

  • "desmarque" la opción "usar este proxy para todos los protocolos"
  • configure el proxy "localhost: 12345" solo como un proxy SOCKS
  • y deje el proxy HTTP, proxy SSL, proxy FTP en blanco

Referencia de documentación oceánica digital

Cómo enrutar el tráfico web de forma segura sin una VPN utilizando un túnel SOCKS

shadi
fuente
1

No creo que "tener conexiones HTTPS a través de servidores proxy" signifique el tipo de ataque Man-in-the-Middle de servidor proxy. Creo que se está preguntando si uno puede conectarse a un servidor proxy http a través de TLS. Y la respuesta es sí.


¿Es posible tener conexiones HTTPS a través de servidores proxy?

Sí, vea mi pregunta y respuesta aquí. El servidor proxy HTTP solo funciona en SwitchOmega

Si es así, ¿qué tipo de servidor proxy permite esto?

El tipo de servidor proxy implementa certificados SSL, como lo hacen los sitios web comunes. Pero necesita un pacarchivo para que el navegador configure la conexión proxy a través de SSL.

Almiar
fuente