代理服务器上的HTTPS连接

时间:2009-02-05 15:20:35

标签: proxy https

是否可以通过代理服务器建立HTTPS连接?如果是,那么什么样的代理服务器允许这样做?

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

重复

9 个答案:

答案 0 :(得分:46)

TLS / SSL(HTTPS中的S)保证您和您正在联系的服务器之间没有窃听者,即没有代理。通常,您使用CONNECT通过代理打开TCP连接。在这种情况下,代理将无法缓存,读取或修改连接,因此无用。

如果您希望代理能够读取信息,您可以采取以下方法:

  1. 客户端启动HTTPS会话
  2. 代理透明地拦截连接和 返回ad-hoc生成(可能 弱证书K a , 由证书颁发机构签名 这是无条件信任的 客户。
  3. 代理启动HTTPS会话到目标
  4. 代理验证SSL的完整性 证书;如果显示错误 证书无效。
  5. 代理流内容,解密它 并用它重新加密 ķ<子>一
  6. 客户端显示内容
  7. 一个例子是Squid的SSL bump。同样,打嗝can be configured来做到这一点。这也是used in a less-benign context by an Egyptian ISP

    请注意,现代网站和浏览器可以使用HPKPbuilt-in certificate pins来破坏这种方法。

答案 1 :(得分:14)

据我所知,您需要在代理上使用HTTP CONNECT查询。这会将请求连接转换为透明的TCP / IP隧道。

因此您需要知道您使用的代理服务器是否支持此协议。

答案 2 :(得分:12)

简短的回答是:可以使用特殊的HTTP代理或SOCKS代理来完成。

首先,HTTPS使用SSL / TLS,它通过在不安全的通道上建立安全通信通道来确保端到端的安全性。如果HTTP代理能够看到内容,那么它就是一个中间人窃听者,这会破坏SSL / TLS的目标。因此,如果我们想通过普通的HTTP代理进行代理,必须要有一些技巧。

诀窍是,我们使用名为CONNECT的特殊命令将HTTP代理转换为TCP代理。并非所有HTTP代理都支持此功能,但现在很多都支持。 TCP代理无法以明文形式查看正在传输的HTTP内容,但这不会影响其来回转发数据包的能力。通过这种方式,客户端和服务器可以在代理的帮助下相互通信。这是代理HTTPS数据的安全方式。

还有一种不安全的方法,即HTTP代理成为中间人。它接收客户端发起的连接,然后启动到真实服务器的另一个连接。在良好实施的SSL / TLS中,将通知客户端代理不是真实服务器。因此,客户端必须通过忽略对工作的警告来信任代理。之后,代理只需解密来自一个连接的数据,重新加密并将其提供给另一个连接。

最后,我们当然可以通过SOCKS代理代理HTTPS,因为SOCKS代理工作在较低级别。您可以将SOCKS代理视为TCP和UDP代理。

答案 3 :(得分:9)

如果它仍然有趣,这里是一个类似问题的答案: Convert HTTP Proxy to HTTPS Proxy in Twisted

回答问题的第二部分:

  

如果是,那是什么样的代理服务器   允许这个?

开箱即用,大多数代理服务器将配置为仅允许HTTPS连接到端口443,因此具有自定义端口的https URI将不起作用。这通常是可配置的,具体取决于代理服务器。例如,Squid和TinyProxy支持这一点。

答案 4 :(得分:5)

这是我的完整Java代码,它使用SOCKS代理支持HTTP和HTTPS请求。

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

答案 5 :(得分:2)

您可以使用动态SSL生成中的中间人技术来实现此目的。看一下mitmproxy - 这是一个基于Python,支持SSL的MITM代理。

答案 6 :(得分:2)

通过SSH(Linux版本)隧道化HTTPS:

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.

答案 7 :(得分:1)

我曾尝试过

  • 开始隧道:ssh -N -D 12345 login@proxy_server
  • 将firefox设置中的代理设置为localhost:12345
    • 并勾选&#34;将此代理用于所有协议&#34;

但这导致错误&#34;不安全的连接&#34;每当我尝试连接到https网站时。

解决方案是

  • &#34;勾去掉&#34; &#34;将此代理用于所有协议&#34;
  • 设置代理&#34; localhost:12345&#34;仅作为SOCKS代理
  • 并保留HTTP代理,SSL代理,FTP代理空白

数字海洋文献的参考

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

答案 8 :(得分:1)

我不认为“通过代理服务器具有HTTPS连接”是指代理服务器的“中间人”攻击类型。我认为这是在问是否可以通过TLS连接到http代理服务器。答案是肯定的。


  

是否可以通过代理服务器建立HTTPS连接?

是,请参阅我的问题和答案 这里。 HTTPs proxy server only works in SwitchOmega

  

如果是,哪种代理服务器允许?

这种代理服务器部署SSL证书,就像普通网站一样。但是,对于浏览器,您需要一个pac文件来配置基于SSL的代理连接。