HttpRoutePlanner - 它如何与 HTTPS 代理一起工作
Posted
技术标签:
【中文标题】HttpRoutePlanner - 它如何与 HTTPS 代理一起工作【英文标题】:HttpRoutePlanner - How does it work with an HTTPS Proxy 【发布时间】:2013-02-09 11:35:28 【问题描述】:我设置了 HTTPS 代理,以便 HTTP 客户端可以安全地将纯 HTTP 请求发送到代理。例如,客户端可以向代理发送加密的 HTTP GET 请求,代理将删除加密并将纯 HTTP GET 请求发送到终端。
我了解到这不是一种常见的设置,只有 Google Chrome 具有支持这种情况的内置功能。 (这里的信息 - http://wiki.squid-cache.org/Features/HTTPS#Encrypted_browser-Squid_connection)。我已经让 Google Chrome 与我的 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 终端站点,代理只能看到 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 终端站点,只有初始 CONNECT 请求应加密到代理。无论如何,后续请求都会被隧道化。
谁能告诉我如何实现这个目标?我相信 HttpRoutePlanner 应该会有所帮助,但我不知道如何。
【问题讨论】:
【参考方案1】:我能够使 Apache HttpClient 4.x 与 HTTPS 代理一起工作。我在问题中提到的 SSLPeerUnverifiedException 被抛出,因为我不信任代理服务器的证书。一旦解决了这个问题,与 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
要使 HttpClient 通过 HTTPS 代理与 HTTP 终端站点通信,路由应该是安全的,但不应该有任何隧道或分层。
【讨论】:
您的示例似乎是关于通过 HTTPS 代理的 HTTP,而不是通过 HTTPS 的 HTTPS。如果您要使用“全部信任”策略,那么使用“双”SSL 层有什么意义......【参考方案2】:Apache HttpClient 4.x 仅通过连接隧道支持通过代理的 SSL。它不支持 HTTPS 代理。
【讨论】:
@MediumOne 相信我,它不起作用。见issues.apache.org/jira/browse/HTTPCLIENT-1318 它确实对我有用。当存在 HTTP 终端站点时,我遇到了与发帖人相同的错误。错误是 -"Unable to establish route: planned = ->https://localhost:7777->;http://www.exceptional.io; current = s->https://localhost:7777->;http://www.exceptional.io"
我能够通过将我自己的 RoutePlanner 设置为“true”来强制建立安全连接。现在计划的路线变成了s->https://localhost:7777->;http://www.exceptional.io"
,我没有看到任何错误。以上是关于HttpRoutePlanner - 它如何与 HTTPS 代理一起工作的主要内容,如果未能解决你的问题,请参考以下文章