HTTPS connections over proxy servers

2020-01-25 12:49发布

Is it possible to have HTTPS connections over proxy servers? If yes, what kind of proxy server allows this?

Duplicated with How to use Socks 5 proxy with Apache HTTP Client 4?

标签: proxy https
9条回答
迷人小祖宗
2楼-- · 2020-01-25 13:00

Here is my complete Java code that supports both HTTP and HTTPS requests using SOCKS proxy.

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楼-- · 2020-01-25 13:04

The short answer is: It is possible, and can be done with either a special HTTP proxy or a SOCKS proxy.

First and foremost, HTTPS uses SSL/TLS which by design ensures end-to-end security by establishing a secure communication channel over an insecure one. If the HTTP proxy is able to see the contents, then it's a man-in-the-middle eavesdropper and this defeats the goal of SSL/TLS. So there must be some tricks being played if we want to proxy through a plain HTTP proxy.

The trick is, we turn an HTTP proxy into a TCP proxy with a special command named CONNECT. Not all HTTP proxies support this feature but many do now. The TCP proxy cannot see the HTTP content being transferred in clear text, but that doesn't affect its ability to forward packets back and forth. In this way, client and server can communicate with each other with help of the proxy. This is the secure way of proxying HTTPS data.

There is also an insecure way of doing so, in which the HTTP proxy becomes a man-in-the-middle. It receives the client-initiated connection, and then initiate another connection to the real server. In a well implemented SSL/TLS, the client will be notified that the proxy is not the real server. So the client has to trust the proxy by ignoring the warning for things to work. After that, the proxy simply decrypts data from one connection, reencrypts and feeds it into the other.

Finally, we can certainly proxy HTTPS through a SOCKS proxy, because the SOCKS proxy works at a lower level. You may think a SOCKS proxy as both a TCP and a UDP proxy.

查看更多
Anthone
4楼-- · 2020-01-25 13:04

I had tried

  • start tunneling: ssh -N -D 12345 login@proxy_server
  • Setting the proxy in the firefox settings as localhost:12345
    • and ticking "use this proxy for all protocols"

but this resulted in the error "Insecure connection" whenever I tried to connect to an https website.

The solution was to

  • "untick" the "use this proxy for all protocols"
  • set the proxy "localhost:12345" only as a SOCKS proxy
  • and leave the HTTP proxy, SSL proxy, FTP proxy blank

Reference from digital ocean documentation

How To Route Web Traffic Securely Without a VPN Using a SOCKS Tunnel

查看更多
做个烂人
5楼-- · 2020-01-25 13:05

tunneling HTTPS through SSH (linux version):

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

everything you do on localhost. then:

target_domain.com is accessible from localhost browser.
查看更多
爱情/是我丢掉的垃圾
6楼-- · 2020-01-25 13:10

I don't think "have HTTPS connections over proxy servers" means the Man-in-the-Middle attack type of proxy server. I think it's asking whether one can connect to a http proxy server over TLS. And the answer is yes.


Is it possible to have HTTPS connections over proxy servers?

Yes, see my question and answer here. HTTPs proxy server only works in SwitchOmega

If yes, what kind of proxy server allows this?

The kind of proxy server deploys SSL certificates, like how ordinary websites do. But you need a pac file for the brower to configure proxy connection over SSL.

查看更多
Root(大扎)
7楼-- · 2020-01-25 13:13

You can accomplish this using man-in-the-middle techniques with dynamic SSL generation. Take a look at mitmproxy - it's a Python based, SSL-capable MITM proxy.

查看更多
登录 后发表回答