[proxy] 프록시 서버를 통한 HTTPS 연결

프록시 서버를 통해 HTTPS 연결이 가능합니까? 그렇다면 어떤 종류의 프록시 서버가이를 허용합니까?

Apache HTTP Client 4에서 Socks 5 프록시를 사용하는 방법 과 중복 됩니까?



답변

TLS / SSL (HTTPS의 S)은 사용자와 연결중인 서버 사이에 도청자가 없음을 보장합니다. 즉, 프록시가 없습니다. 일반적으로 CONNECT프록시를 통해 TCP 연결을 여는 데 사용 합니다. 이 경우 프록시는 요청 / 응답을 캐시, 읽기 또는 수정할 수 없으므로 다소 쓸모가 없습니다.

프록시가 정보를 읽을 수 있도록하려면 다음 접근 방식을 사용할 수 있습니다.

  1. 클라이언트가 HTTPS 세션을 시작합니다.
  2. 프록시는 연결을 투명하게 가로 채고 클라이언트가 무조건 신뢰하는 인증 기관에서 서명 한 임시 생성 (약한) 인증서 K a를 반환합니다 .
  3. 프록시가 대상으로 HTTPS 세션을 시작합니다.
  4. 프록시는 SSL 인증서의 무결성을 확인합니다. 인증서가 유효하지 않은 경우 오류를 표시합니다.
  5. 프록시는 콘텐츠를 스트리밍하고 해독 한 다음 K a로 다시 암호화합니다 .
  6. 클라이언트 디스플레이 물건

예는 Squid의 SSL bump 입니다. 마찬가지로 트림 을 구성 하여이를 수행 할 수 있습니다 . 이것은 또한 이집트 ISP에 의해 덜 양성적인 맥락에서 사용 되었습니다 .

최신 웹 사이트와 브라우저는 HPKP 또는 이 접근 방식을 무력화하는 내장 인증서 핀 을 사용할 수 있습니다 .


답변

짧은 대답은 다음과 같습니다. 가능하며 특수 HTTP 프록시 또는 SOCKS 프록시를 사용하여 수행 할 수 있습니다.

무엇보다도 HTTPS는 SSL / TLS를 사용합니다. SSL / TLS는 설계 상 안전하지 않은 통신 채널을 통해 보안 통신 채널을 설정하여 종단 간 보안을 보장합니다. HTTP 프록시가 콘텐츠를 볼 수 있다면 중간자 도청 자이며 이것은 SSL / TLS의 목표를 무력화시킵니다. 따라서 일반 HTTP 프록시를 통해 프록시하려면 몇 가지 트릭이 있어야합니다.

트릭은라는 특수 명령을 사용하여 HTTP 프록시를 TCP 프록시로 전환하는 것 CONNECT입니다. 모든 HTTP 프록시가이 기능을 지원하는 것은 아니지만 현재 많은 프록시가 지원합니다. TCP 프록시는 일반 텍스트로 전송되는 HTTP 콘텐츠를 볼 수 없지만 패킷을 앞뒤로 전달하는 기능에는 영향을주지 않습니다. 이러한 방식으로 클라이언트와 서버는 프록시를 사용하여 서로 통신 할 수 있습니다. 이것은 HTTPS 데이터를 프록시하는 안전한 방법입니다.

HTTP 프록시가 중간자 (man-in-the-middle)가되는 안전하지 않은 방법도 있습니다. 클라이언트가 시작한 연결을 수신 한 다음 실제 서버에 대한 다른 연결을 시작합니다. 잘 구현 된 SSL / TLS에서 클라이언트는 프록시가 실제 서버가 아니라는 알림을받습니다. 따라서 클라이언트는 작업에 대한 경고를 무시하여 프록시를 신뢰해야합니다. 그 후 프록시는 한 연결에서 데이터를 해독하고 다시 암호화하여 다른 연결로 공급합니다.

마지막으로 SOCKS 프록시가 낮은 수준에서 작동하기 때문에 SOCKS 프록시를 통해 HTTPS를 확실히 프록시 할 수 있습니다 . SOCKS 프록시를 TCP 및 UDP 프록시로 생각할 수 있습니다.


답변

내가 기억할 수있는 한 프록시에서 HTTP CONNECT 쿼리를 사용해야합니다. 그러면 요청 연결이 투명한 TCP / IP 터널로 변환됩니다.

따라서 사용하는 프록시 서버가이 프로토콜을 지원하는지 알아야합니다.


답변

여전히 관심이 있다면 유사한 질문에 대한 답변입니다.
Twisted에서 HTTP 프록시를 HTTPS 프록시로 변환

질문의 두 번째 부분에 답하려면 :

그렇다면 어떤 종류의 프록시 서버가이를 허용합니까?

기본적으로 대부분의 프록시 서버는 포트 443에만 HTTPS 연결을 허용하도록 구성되므로 사용자 지정 포트가있는 https URI는 작동하지 않습니다. 일반적으로 프록시 서버에 따라 구성 할 수 있습니다. 예를 들어 Squid와 TinyProxy는이를 지원합니다.


답변

다음은 SOCKS 프록시를 사용하여 HTTP 및 HTTPS 요청을 모두 지원하는 완전한 Java 코드입니다.

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);
        }
    }
}


답변

동적 SSL 생성과 함께 중간자 (man-in-the-middle) 기술을 사용하여이를 수행 할 수 있습니다. mitmproxy를 살펴보십시오 -Python 기반의 SSL 지원 MITM 프록시입니다.


답변

SSH를 통한 HTTPS 터널링 (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

localhost에서하는 모든 것. 그때:

target_domain.com is accessible from localhost browser.