프록시 서버를 통한 HTTPS 연결


103

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

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



예, 가능합니다. 여기에서 실제 예제를 참조하십시오. stackoverflow.com/questions/56981993/…
Rick

답변:


66

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

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

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

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

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


13
이것은 원칙적으로 작동 할 수 있지만 브라우저가 HTTPS 요청을 위해 HTTP 프록시와 통신하는 방식은 아닙니다. 여기에 설명 된 방식은 프록시 서버가 사실상 Man-In-The-Middle이라는 것을 의미합니다 (따라서 그에 따라 신뢰할 수 있어야 함).
Bruno

5
오징어가 이렇게합니다. SSL Bump 라고 합니다 .
Adam Mackler 2013 년

3
최종 사용자에게 많은 경고 없이는 작동하지 않습니다. "고객이 무조건 신뢰"-그런 것은 없습니다. 인증서가 완벽하더라도 AAA +++는 최종 사용자가 요청한 것과 일치하지 않는 다른 도메인을 보여 주므로 정상적인 브라우저 (여기서는 IE를 의미하지 않음 ...)가 위아래로 비명을 지르게됩니다. 물론 SSL 검사를 비활성화하는 매개 변수와 함께 wget을 사용할 수 있지만 무엇을 추측할까요? 핵심 보안 검사가 비활성화 된 후에는이 연결의 이름을 "SSL"로 지정할 수 없습니다.
Van Jone 2015

1
@Van Jone Unconditionally trusted은 CA 인증서를 나타냅니다. CA 인증서에는 도메인이 없습니다. 사용자에게 알리지 않고 실제로 작동하는 두 가지 예를 사용하여 답변을 수정했습니다.
phihag

6
내 대답은 "가짜 CA"라고 부르는 것에 의존합니다. 한 CA의 인증서가 되어 무조건 같은 (예를 들어, 엔터프라이즈 구성 또는 악성 코드에 대한 자신의 컴퓨터 또는 소프트웨어) 사용자가 그런 식으로 구성하거나, CA는 CA의 중 하나에서 얻은 때문에 주요 브라우저, 신뢰 중 하나 때문에, 신뢰 MCS의 경우. 프록시는 클라이언트가 요청하는 모든 도메인에 대해 새로운 유효한 인증서를 생성하므로 답변 끝에 언급 된 anti-MITM 기능이 없으면 클라이언트는 알 수 없습니다.
phihag 2015

22

짧은 대답은 다음과 같습니다. 가능하며 특수 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 프록시로 생각할 수 있습니다.


CONNECT를 사용하면 stackoverflow.com/a/3118759/632951에 언급 된 보안 경고가 발생 합니까?
Pacerier

@Pacerier 그렇게 생각하지 않습니다. CONNECT 모드에서 프록시는 전송 계층에서 작동합니다.
Cyker

그렇다면 CONNECT 방법으로 클라이언트의 https 데이터 가 중개 프록시의 응용 프로그램 수준 으로 전달되지 않습니까? 그리고 프록시의 TCP 수준에서 평가하고 원격 서버로 직접 중계 합니까?
zzinny

15

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

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


3
실제로 클라이언트는 CONNECT 동사를 사용하여 HTTP 프록시 서버를 통해 https : // URI를 사용합니다. 이 경우 연결은 프록시를 통해 터널링되므로 클라이언트가 최종 서버와 직접 통신하는 것처럼 인증서 확인이 평소와 같이 수행됩니다.
Bruno

1
@chburd,하지만 프록시는 일반적으로 HTTP CONNECT를 지원합니까?
Pacerier

9

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

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

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

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


5

다음은 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);
        }
    }
}

3

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


3

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.

1

나는 시도했다

  • 터널링 시작 : ssh -N -D 12345 login@proxy_server
  • firefox 설정에서 프록시 설정 localhost:12345
    • "모든 프로토콜에이 프록시 사용"을 선택합니다.

하지만 이로 인해 https 웹 사이트에 연결할 때마다 "안전하지 않은 연결"오류가 발생했습니다.

해결책은

  • "모든 프로토콜에이 프록시 사용"을 "선택 해제"합니다.
  • 프록시 "localhost : 12345"를 SOCKS 프록시로만 설정
  • HTTP 프록시, SSL 프록시, FTP 프록시는 비워 둡니다.

디지털 오션 문서에서 참조

SOCKS 터널을 사용하여 VPN없이 웹 트래픽을 안전하게 라우팅하는 방법


1

"프록시 서버를 통한 HTTPS 연결 있음"은 중간자 공격 유형의 프록시 서버를 의미하지 않습니다. TLS를 통해 http 프록시 서버에 연결할 수 있는지 묻는 것 같습니다. 그리고 대답은 '예'입니다.


프록시 서버를 통해 HTTPS 연결이 가능합니까?

예, 여기에서 내 질문과 답변을 참조하십시오. HTTPs 프록시 서버는 SwitchOmega에서만 작동합니다.

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

프록시 서버의 종류는 일반 웹 사이트와 마찬가지로 SSL 인증서를 배포합니다. 하지만 pac브라우저가 SSL을 통한 프록시 연결을 구성하려면 파일 이 필요 합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.