Conexões HTTPS em servidores proxy


Respostas:


66

TLS / SSL (O S em HTTPS) garante que não haja bisbilhoteiros entre você e o servidor que está contatando, ou seja, sem proxies. Normalmente, você usa CONNECTpara abrir uma conexão TCP por meio do proxy. Nesse caso, o proxy não será capaz de armazenar em cache, ler ou modificar nenhuma solicitação / resposta e, portanto, será bastante inútil.

Se quiser que o proxy possa ler as informações, você pode seguir a seguinte abordagem:

  1. Cliente inicia sessão HTTPS
  2. O proxy intercepta a conexão de forma transparente e retorna um certificado K a gerado ad-hoc (possivelmente fraco) , assinado por uma autoridade de certificação em que o cliente confia incondicionalmente.
  3. O proxy inicia a sessão HTTPS para o destino
  4. O proxy verifica a integridade do certificado SSL; exibe erro se o certificado não for válido.
  5. O proxy transmite conteúdo, descriptografa e criptografa novamente com K a
  6. Cliente exibe coisas

Um exemplo é o aumento de SSL do Squid . Da mesma forma, o arroto pode ser configurado para fazer isso. Isso também foi usado em um contexto menos benigno por um ISP egípcio .

Observe que os sites e navegadores modernos podem empregar HPKP ou pinos de certificado embutidos que contrariam essa abordagem.


13
Isso poderia funcionar em princípio, mas não é assim que os navegadores se comunicam com proxies HTTP para solicitações HTTPS. A maneira como é descrito aqui implica que o servidor proxy é efetivamente um Man-In-The-Middle (portanto, deve ser confiável).
Bruno

5
O Squid faz isso. É chamado de SSL Bump .
Adam Mackler

3
Não funcionará sem muitos alertas para o usuário final. "confiança incondicional do cliente" - não existe tal coisa. Mesmo que o cert seja perfeito-AAA +++, ele ainda mostra domínios diferentes que não correspondem ao que o usuário final pediu, o que fará qualquer navegador lógico (não significando o IE aqui ...) pulando para cima e para baixo gritando. Claro, é possível usar wget com parâmetros que desabilitam as verificações de SSL, mas adivinhe? esta conexão não pode mais ser chamada de "SSL" depois que suas verificações de segurança centrais foram desabilitadas.
Van Jone

1
@Van Jone Unconditionally trustedrefere-se a um certificado CA. Certos de CA não têm domínios. Eu alterei a resposta com dois exemplos em que isso funciona / funcionou na prática, sem nenhum alerta para o usuário.
phihag de

6
Minha resposta depende do que você chama de "CA falsa". O certificado da CA é incondicionalmente confiável, seja porque o usuário (ou software em seu computador, por exemplo, configuração corporativa ou malware) o configurou dessa forma, ou porque a CA foi obtida de uma das CAs confiáveis ​​pelos principais navegadores, como no caso MCS. O proxy gera um novo certificado válido para cada domínio que o cliente solicitar, portanto, sem os recursos anti-MITM mencionados no final da resposta, o cliente não perceberá.
phihag de

22

A resposta curta é: É possível e pode ser feito com um proxy HTTP especial ou um proxy SOCKS.

Em primeiro lugar, HTTPS usa SSL / TLS que, por design, garante segurança ponta a ponta, estabelecendo um canal de comunicação seguro em vez de um inseguro. Se o proxy HTTP é capaz de ver o conteúdo, então ele é um bisbilhoteiro man-in-the-middle e isso vai contra o objetivo do SSL / TLS. Portanto, deve haver alguns truques sendo jogados se quisermos proxy através de um proxy HTTP simples.

O truque é transformar um proxy HTTP em um proxy TCP com um comando especial chamado CONNECT. Nem todos os proxies HTTP oferecem suporte a esse recurso, mas muitos o fazem agora. O proxy TCP não pode ver o conteúdo HTTP sendo transferido em texto não criptografado, mas isso não afeta sua capacidade de encaminhar pacotes para frente e para trás. Dessa forma, o cliente e o servidor podem se comunicar com a ajuda do proxy. Esta é a maneira segura de fazer proxy de dados HTTPS.

Também existe uma maneira insegura de fazer isso, em que o proxy HTTP se torna um intermediário. Ele recebe a conexão iniciada pelo cliente e, em seguida, inicia outra conexão com o servidor real. Em um SSL / TLS bem implementado, o cliente será notificado de que o proxy não é o servidor real. Portanto, o cliente precisa confiar no proxy, ignorando o aviso para que as coisas funcionem. Depois disso, o proxy simplesmente descriptografa os dados de uma conexão, criptografa novamente e os alimenta na outra.

Finalmente, podemos certamente fazer proxy HTTPS por meio de um proxy SOCKS , porque o proxy SOCKS funciona em um nível inferior. Você pode pensar em um proxy SOCKS como um proxy TCP e UDP.


Usar CONNECT causaria avisos de segurança conforme mencionado em stackoverflow.com/a/3118759/632951 ?
Pacerier,

@Pacerier Acho que não. No modo CONNECT, o proxy trabalha na camada de transporte.
Cyker

Então, pelo método CONNECT, algum dado https do cliente não é passado para o nível de aplicativo do proxy intermediário? E apenas avaliado no nível do proxy TCP e retransmitido para o servidor remoto diretamente ?
zzinny

15

tanto quanto me lembro, você precisa usar uma consulta HTTP CONNECT no proxy. isso converterá a conexão solicitada em um túnel TCP / IP transparente.

então você precisa saber se o servidor proxy que você usa suporta este protocolo.


3
Na verdade, os clientes usam o verbo CONNECT para usar URIs https: // por meio de servidores proxy HTTP. Neste caso, a conexão é feita através do proxy, de forma que a verificação do certificado é feita normalmente, como se o cliente estivesse falando diretamente com o servidor final.
Bruno

1
@chburd, mas os proxies geralmente suportam HTTP CONNECT?
Pacerier,

9

Se ainda for de interesse, aqui está uma resposta a uma pergunta semelhante: Converter proxy HTTP em proxy HTTPS no Twisted

Para responder à segunda parte da pergunta:

Se sim, que tipo de servidor proxy permite isso?

Por padrão, a maioria dos servidores proxy será configurada para permitir conexões HTTPS apenas para a porta 443, portanto, URIs https com portas personalizadas não funcionarão. Isso geralmente é configurável, dependendo do servidor proxy. Squid e TinyProxy suportam isso, por exemplo.


5

Aqui está meu código Java completo que suporta solicitações HTTP e HTTPS usando o 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);
        }
    }
}

3

Você pode fazer isso usando técnicas man-in-the-middle com geração SSL dinâmica. Dê uma olhada no mitmproxy - é um proxy MITM baseado em Python e compatível com SSL.


3

tunelando HTTPS através de SSH (versão 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

tudo o que você faz no localhost. então:

target_domain.com is accessible from localhost browser.

1

Eu tentei

  • iniciar o tunelamento: ssh -N -D 12345 login@proxy_server
  • Definir o proxy nas configurações do firefox como localhost:12345
    • e marcando "usar este proxy para todos os protocolos"

mas isso resultava no erro "Conexão insegura" sempre que tentava me conectar a um site https.

A solução era

  • "desmarque" a opção "usar este proxy para todos os protocolos"
  • defina o proxy "localhost: 12345" apenas como um proxy SOCKS
  • e deixe o proxy HTTP, proxy SSL, proxy FTP em branco

Referência da documentação digital do oceano

Como rotear o tráfego da Web com segurança sem VPN usando um túnel SOCKS


1

Não acho que "ter conexões HTTPS em servidores proxy" significa o tipo de ataque Man-in-the-Middle de servidor proxy. Acho que está perguntando se é possível conectar a um servidor proxy http por TLS. E a resposta é sim.


É possível ter conexões HTTPS em servidores proxy?

Sim, veja minha pergunta e resposta aqui. O servidor proxy HTTPs só funciona em SwitchOmega

Se sim, que tipo de servidor proxy permite isso?

O tipo de servidor proxy implanta certificados SSL, como fazem os sites comuns. Mas você precisa de um pacarquivo para o navegador configurar a conexão proxy sobre SSL.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.