프록시 서버를 통해 HTTPS 연결이 가능합니까? 그렇다면 어떤 종류의 프록시 서버가이를 허용합니까?
답변
TLS / SSL (HTTPS의 S)은 사용자와 연결중인 서버 사이에 도청자가 없음을 보장합니다. 즉, 프록시가 없습니다. 일반적으로 CONNECT
프록시를 통해 TCP 연결을 여는 데 사용 합니다. 이 경우 프록시는 요청 / 응답을 캐시, 읽기 또는 수정할 수 없으므로 다소 쓸모가 없습니다.
프록시가 정보를 읽을 수 있도록하려면 다음 접근 방식을 사용할 수 있습니다.
- 클라이언트가 HTTPS 세션을 시작합니다.
- 프록시는 연결을 투명하게 가로 채고 클라이언트가 무조건 신뢰하는 인증 기관에서 서명 한 임시 생성 (약한) 인증서 K a를 반환합니다 .
- 프록시가 대상으로 HTTPS 세션을 시작합니다.
- 프록시는 SSL 인증서의 무결성을 확인합니다. 인증서가 유효하지 않은 경우 오류를 표시합니다.
- 프록시는 콘텐츠를 스트리밍하고 해독 한 다음 K a로 다시 암호화합니다 .
- 클라이언트 디스플레이 물건
예는 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.