我设置了HTTPS代理,以便HTTP客户端可以安全地向代理发送纯HTTP请求。例如,客户端可以向代理发送加密的HTTP GET请求,该请求将删除加密并将纯HTTP GET请求发送到终端站点。
我了解到这不是一种常见的设置,只有Google Chrome具有支持此类方案的内置功能。 (信息在这里 - http://wiki.squid-cache.org/Features/HTTPS#Encrypted_browser-Squid_connection)。我已将谷歌浏览器与我的HTTPS代理一起使用,因此代理方面没有问题。
我希望编写一个HTTP客户端来加密对我的HTTPS代理的所有请求。我尝试以这种方式将HTTPS代理设置为DefaultHttpClient -
DefaultHttpClient dhc = new DefaultHttpClient();
HttpHost proxy = new HttpHost("192.168.2.3", 8181, "https"); //NOTE : https
dhc.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
然后尝试执行任何请求会给我一个SSLPeerUnverifiedException。我不明白为什么。
在我探索DefaultHttpClient API的过程中,我遇到了HttpRoutePlanner和HttpRoute,我们可以使用它来指定代理的连接是否应该加密。但是,我无法完成这项工作。
这是一个通过区分HTTP代理设置来解释我的设置的图表 -
HTTP代理:
HTTP Client <------- Plain Text GET, POST Requests -------> HTTP Proxy <------- Plain Text GET, POST Requests -------> HTTP End-Site
HTTP Client <------- Plain Text CONNECT Requests -------> HTTP Proxy <------- Plain Text CONNECT Requests -------> HTTPS End-Site
注意:对于HTTPS End-Sites,代理只能看到CONNECT请求。然后在客户端和终端站点之间建立SSL隧道
HTTPS代理:
HTTP Client <------- Encrypted GET, POST Requests -------> HTTPS Proxy <-------- Plain Text GET, POST Requests --------> HTTP End-Site
HTTP Client <------- Encrypted CONNECT Requests -------> HTTPS Proxy <------- Plain Text CONNECT Requests -------> HTTPS End-Site
注意:对于HTTPS End-Sites,只应将初始CONNECT请求加密到代理。无论如何,随后的请求将被隧道化。
任何人都可以告诉我如何实现这一目标吗?我相信HttpRoutePlanner应该有所帮助,但我不知道如何。
答案 0 :(得分:3)
我能够使Apache HttpClient 4.x与HTTPS代理一起工作。我在问题中提到的SSLPeerUnverifiedException被抛出,因为我不信任Proxy Server的证书。完成此操作后,与HTTPS终端站点的连接按预期工作。
对于HTTP终端站点的连接,我必须使用自己的HttpRoutePlanner才能使其正常工作。这是带有解释的代码 -
DefaultHttpClient dhc = new DefaultHttpClient();
HttpHost proxy = new HttpHost("192.168.2.3", 8181, "https");
dhc.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
SchemeSocketFactory factory = null;
try {
factory = new SSLSocketFactory(new SimpleTrustStrategy()); //Trust All strategy
} catch (GeneralSecurityException e1) {
e1.printStackTrace();
}
Scheme https = new Scheme("https", 443, factory);
dhc.getConnectionManager().getSchemeRegistry().register(https);
HttpGet request = new HttpGet("http://en.wikipedia.org/wiki/Main_Page");
try {
HttpHost host = determineTarget(request);
if(host.getSchemeName().equalsIgnoreCase("http")){
dhc.setRoutePlanner(new MyRoutePlanner());
}
} catch (ClientProtocolException e1) {
e1.printStackTrace();
}
MyRoutePlanner
的实施情况如下 -
public class MyRoutePlanner implements HttpRoutePlanner {
@Override
public HttpRoute determineRoute(HttpHost target, HttpRequest request,
HttpContext context) throws HttpException {
return new HttpRoute(target, null
, new HttpHost("192.168.2.3", 8181, "https")
, true, TunnelType.PLAIN, LayerType.PLAIN); //Note: true
}
}
要通过HTTPS代理使HttpClient与HTTP终端站点通信,路由应该是安全的,但不应该有任何隧道或分层。
答案 1 :(得分:0)
Apache HttpClient 4.x仅通过连接隧道仅通过代理支持SSL。它不支持HTTPS代理。