Połączenia HTTPS przez serwery proxy


Odpowiedzi:


66

TLS / SSL (S w HTTPS) gwarantuje, że między tobą a serwerem, z którym się kontaktujesz, nie ma żadnych podsłuchiwaczy, tj. Żadnych serwerów proxy. Zwykle używasz CONNECTdo otwierania połączenia TCP przez proxy. W takim przypadku proxy nie będzie w stanie buforować, czytać ani modyfikować żadnych żądań / odpowiedzi, a zatem będzie raczej bezużyteczne.

Jeśli chcesz, aby serwer proxy mógł odczytywać informacje, możesz zastosować następujące podejście:

  1. Klient rozpoczyna sesję HTTPS
  2. Proxy w przejrzysty sposób przechwytuje połączenie i zwraca wygenerowany ad-hoc (prawdopodobnie słaby) certyfikat K a , podpisany przez urząd certyfikacji, któremu klient bezwarunkowo ufa.
  3. Proxy uruchamia sesję HTTPS do celu
  4. Proxy weryfikuje integralność certyfikatu SSL; wyświetla błąd, jeśli certyfikat jest nieprawidłowy.
  5. Proxy przesyła strumieniowo zawartość, odszyfrowuje ją i ponownie szyfruje za pomocą K a
  6. Klient wyświetla rzeczy

Przykładem jest bump SSL Squid . Podobnie, beknięcie można skonfigurować, aby to zrobić. Zostało to również użyte w mniej łagodnym kontekście przez egipskiego dostawcę usług internetowych .

Zauważ, że nowoczesne strony internetowe i przeglądarki mogą wykorzystywać HPKP lub wbudowane szpilki certyfikatów, które pokonują to podejście.


13
W zasadzie może to zadziałać, ale nie w ten sposób przeglądarki komunikują się z serwerami proxy HTTP w przypadku żądań HTTPS. Sposób, w jaki jest to tutaj opisane, sugeruje, że serwer proxy jest w rzeczywistości Man-In-The-Middle (więc należałoby mu odpowiednio zaufać).
Bruno,

5
Squid to robi. Nazywa się SSL Bump .
Adam Mackler,

3
Nie będzie działać bez wielu alertów dla użytkownika końcowego. „bezwarunkowo zaufany przez klienta” - czegoś takiego nie ma. Nawet jeśli certyfikat jest doskonały - AAA +++, nadal pokazuje inną domenę nie pasującą do tego, o co prosił użytkownik końcowy, co spowoduje, że każda rozsądna przeglądarka (nie oznacza to IE tutaj ...) będzie podskakiwać z krzykiem. Oczywiście można użyć wget z parametrami wyłączającymi sprawdzanie SSL, ale wiecie co? to połączenie nie może już nazywać się „SSL” po wyłączeniu jego podstawowych kontroli bezpieczeństwa.
Van Jone

1
@ Van Jone Unconditionally trustedodnosi się do certyfikatu CA. Certyfikaty CA nie mają domen. Poprawiłem odpowiedź, podając dwa przykłady, w których to działa / działało w praktyce bez żadnych ostrzeżeń dla użytkownika.
phihag

6
Moja odpowiedź opiera się na tym, co nazywasz „fałszywym urzędem certyfikacji”. Certyfikat urzędu certyfikacji jest bezwarunkowo zaufany, ponieważ użytkownik (lub oprogramowanie na jego komputerze, na przykład konfiguracja przedsiębiorstwa lub złośliwe oprogramowanie) skonfigurował go w ten sposób, albo ponieważ CA został uzyskany z jednego z CA zaufanych przez główne przeglądarki, np. w przypadku MCS. Proxy generuje nowy ważny certyfikat dla każdej domeny, której żąda klient, więc bez funkcji anty-MITM wspomnianych na końcu odpowiedzi klient nie zauważy.
phihag

23

Krótka odpowiedź brzmi: jest to możliwe i można to zrobić za pomocą specjalnego serwera proxy HTTP lub serwera proxy SOCKS.

Przede wszystkim HTTPS wykorzystuje SSL / TLS, który z założenia zapewnia pełne bezpieczeństwo, ustanawiając bezpieczny kanał komunikacyjny nad niezabezpieczonym. Jeśli serwer proxy HTTP jest w stanie zobaczyć zawartość, oznacza to, że jest podsłuchiwaczem typu „pośrednik”, co jest sprzeczne z celem SSL / TLS. Musimy więc zastosować pewne sztuczki, jeśli chcemy korzystać z proxy przez zwykły serwer proxy HTTP.

Sztuczka polega na tym, że zmieniamy proxy HTTP w proxy TCP za pomocą specjalnego polecenia o nazwie CONNECT. Nie wszystkie serwery proxy HTTP obsługują tę funkcję, ale wiele z nich teraz. Serwer proxy TCP nie widzi przesyłanej zawartości HTTP w postaci zwykłego tekstu, ale nie wpływa to na jego zdolność do przekazywania pakietów w tę iz powrotem. W ten sposób klient i serwer mogą komunikować się ze sobą za pomocą proxy. Jest to bezpieczny sposób przekazywania danych HTTPS przez proxy.

Istnieje również niebezpieczny sposób na zrobienie tego, w którym proxy HTTP staje się pośrednikiem. Otrzymuje połączenie inicjowane przez klienta, a następnie inicjuje kolejne połączenie z rzeczywistym serwerem. W dobrze zaimplementowanym protokole SSL / TLS klient zostanie powiadomiony, że serwer proxy nie jest prawdziwym serwerem. Dlatego klient musi ufać proxy, ignorując ostrzeżenie, że wszystko działa. Następnie proxy po prostu odszyfrowuje dane z jednego połączenia, ponownie szyfruje i przekazuje je do drugiego.

Wreszcie, z pewnością możemy proxy HTTPS przez proxy SOCKS , ponieważ proxy SOCKS działa na niższym poziomie. Możesz myśleć, że proxy SOCKS jest zarówno proxy TCP, jak i UDP.


Czy użycie CONNECT spowodowałoby ostrzeżenia bezpieczeństwa, o których mowa na stackoverflow.com/a/3118759/632951 ?
Pacerier,

@Pacerier Nie sądzę. W trybie CONNECT proxy działa w warstwie transportowej.
Cyker

Czyli metodą CONNECT żadne dane https z klienta nie są przekazywane do poziomu aplikacji pośredniczącego serwera proxy? Czy po prostu oceniono na poziomie proxy TCP i przekazano bezpośrednio do zdalnego serwera ?
zzinny

15

O ile pamiętam, na serwerze proxy należy użyć zapytania HTTP CONNECT. spowoduje to przekształcenie połączenia żądającego w przezroczysty tunel TCP / IP.

więc musisz wiedzieć, czy serwer proxy, którego używasz, obsługuje ten protokół.


3
Rzeczywiście, klienci używają zlecenia CONNECT, aby używać identyfikatorów URI https: // za pośrednictwem serwerów proxy HTTP. W tym przypadku połączenie jest tunelowane przez proxy, więc weryfikacja certyfikatu przebiega normalnie, tak jakby klient rozmawiał bezpośrednio z serwerem końcowym.
Bruno,

1
@chburd, ale czy serwery proxy zazwyczaj obsługują protokół HTTP CONNECT?
Pacerier,

9

Jeśli nadal jest to interesujące, oto odpowiedź na podobne pytanie: Konwertuj serwer proxy HTTP na serwer proxy HTTPS w skręconym

Aby odpowiedzieć na drugą część pytania:

Jeśli tak, jaki rodzaj serwera proxy na to pozwala?

Po wyjęciu z pudełka większość serwerów proxy zostanie skonfigurowanych tak, aby zezwalać na połączenia HTTPS tylko do portu 443, więc identyfikatory URI HTTPS z niestandardowymi portami nie będą działać. Jest to zazwyczaj konfigurowalne, w zależności od serwera proxy. Obsługują to na przykład Squid i TinyProxy.


5

Oto mój kompletny kod Java, który obsługuje zarówno żądania HTTP, jak i HTTPS przy użyciu serwera 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

Możesz to osiągnąć za pomocą technik man-in-the-middle z dynamicznym generowaniem SSL. Przyjrzyj się mitmproxy - jest to oparty na Pythonie serwer proxy MITM z obsługą SSL.


3

tunelowanie HTTPS przez SSH (wersja 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

wszystko, co robisz na hoście lokalnym. następnie:

target_domain.com is accessible from localhost browser.

1

Próbowałem

  • rozpocznij tunelowanie: ssh -N -D 12345 login@proxy_server
  • Ustawienie serwera proxy w ustawieniach przeglądarki Firefox jako localhost:12345
    • i zaznaczając „użyj tego serwera proxy dla wszystkich protokołów”

ale powodowało to błąd „Niezabezpieczone połączenie” za każdym razem, gdy próbowałem połączyć się z witryną https.

Rozwiązaniem było

  • „odznacz” opcję „użyj tego serwera proxy dla wszystkich protokołów”
  • ustaw proxy „localhost: 12345” tylko jako proxy SOCKS
  • i pozostaw puste proxy HTTP, SSL proxy, FTP proxy

Odniesienie z cyfrowej dokumentacji oceanu

Jak bezpiecznie kierować ruch internetowy bez VPN za pomocą tunelu SOCKS


1

Nie sądzę, że „mieć połączenia HTTPS przez serwery proxy” oznacza typ ataku typu Man-in-the-Middle na serwer proxy. Myślę, że pyta, czy można połączyć się z serwerem proxy HTTP przez TLS. A odpowiedź brzmi: tak.


Czy można mieć połączenia HTTPS przez serwery proxy?

Tak, zobacz moje pytanie i odpowiedź tutaj. Serwer proxy HTTPs działa tylko w SwitchOmega

Jeśli tak, jaki rodzaj serwera proxy na to pozwala?

Ten rodzaj serwera proxy wdraża certyfikaty SSL, tak jak robią to zwykłe witryny internetowe. Potrzebujesz jednak pacpliku dla przeglądarki, aby skonfigurować połączenie proxy przez SSL.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.