2013-05-03 115 views
6

我正在为教育目的用Java编写一个简单的HTTPS代理程序。我的程序在端口(例如)上侦听来自浏览器的传入HTTPS请求(如Firefox),解析请求并将其转发到所需目标(如https://www.comodo.com)。用Java实现简单的HTTPS代理应用程序?

Firefox的代理设置被设置为使用我的端口进行SSL连接(127.0.0.1 : 7443)。

我的代码很简短:

static // initializer 
{ 
    System.setProperty("javax.net.ssl.keyStore", "MyKeyStore"); 
    System.setProperty("javax.net.ssl.keyStorePassword", "password"); 
} 

SSLServerSocketFactory ssFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 

try { 
    SSLServerSocket listener = (SSLServerSocket) ssFactory.createServerSocket(port, 64); 
    listener.setUseClientMode(false); 
    listener.setWantClientAuth(false); 
    listener.setNeedClientAuth(false); 

    SSLSocket connection = (SSLSocket) listener.accept(); 
    browser.startHandshake(); /* <<== Exception throws at this line */ 

} catch (IOException ex) { 
    ex.printStackTrace(System.err); 
} 

但是我赶上了以下异常:

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? 

例外说,连接可以是纯文本,但只有HTTPS连接从Firefox设置为使用此端口。我已经记录了哪些Firefox是发送到我的应用程序,它是这样的:

CONNECT www.comodo.com:443 HTTP/1.1 
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0 
Proxy-Connection: keep-alive 
Connection: keep-alive 
Host: www.comodo.com 

火狐在谈论佩林文本,我认为CONNECT是SOCKS命令(我不知道虽然),在那里我有没有在Firefox的SOCKS设置中设置任何内容。下面是Firefox的代理设置截图:

Firefox Proxy Settings

缺少什么我在这里?!我需要做什么才能使这个工作与Firefox或任何其他浏览器?!

---------------------------------------------- --------------------------------

对于那些认为这是another question的重复,并且它有在另一个我不得不说的问题上得到了回答:是的,这两个问题都有类似问题的根源,但是引用问题中的唯一答案指向使用SSL套接字,结果导致这个新问题。因此,尽管这些问题针对的是类似的问题,但这个问题表明了解决问题的完全不同而又误导的路径,因此它可以为将来面临这样一个问题的人们提供有用的指导。

+1

这不是所引用问题的重复。这两个问题明显不同,在引用的问题中没有可接受的解决方案。 – 2013-05-05 11:03:17

+0

对于那些最终在这个线程中的人:您可能对_TheConstructor_的工作示例感兴趣:http://stackoverflow.com/questions/16351413/java-https-proxy-using-https-proxyport-and-https-代理主机 – Trinimon 2015-12-04 15:35:15

回答

6

摆脱所有的SSL。只需处理传入的CONNECT命令,与上游服务器建立明文连接,然后开始复制字节。浏览器和服务器会说SSL,但你根本不需要。

+0

我不认为这是正确的...我以前已经尝试过这种解决方案,它没有工作...你可以看看我以前的问题关于这个解决方案在http://stackoverflow.com/questions/14153662/java-https-connection-forwarding – 2013-05-05 06:09:12

+1

当然,这是正确的。请参阅RFC。很显然,浏览器正在以明文形式发送CONNECT命令,显然你可以推断出它期望以明文形式回复,显然如果你在两个方向上传输所有其他字节而不需要进一步干预,那么存在的任何问题都必须在服务器或浏览器结束。你需要比“它没有工作”更具体。你引用的另一个问题也没有提供任何进一步的信息。 – EJP 2013-05-05 10:11:53

+0

正如我所说的,我已经尝试了你的建议,实际上这是我想到的第一种方法,但它失败了。正如我提供的另一个问题所述,将浏览器的'CONNECT'请求转发给服务器总是会导致'连接重置'错误,这意味着服务器不响应并关闭连接......这种行为很明显,因为服务器正在侦听443上的SSL/TLS'HELLO'消息,并且它获得了'CONNECT',这不是预期的SSL/TLS消息。 – 2013-05-05 10:57:41

3

您的设置正在使用HTTP隧道,其中发送到代理的初始请求是而不是 SSL已加密;由于支持SSL的套接字需要SSL握手,因此会引发异常。

在该机构中,客户要求的HTTP代理服务器转发使用“CONNECT” HTTP 方法 TCP连接到期望的目的地。然后服务器继续代表客户端 进行连接。一旦服务器建立了连接, 代理服务器将继续代理与客户端之间的TCP流,以及来自 客户端的TCP流。请注意,只有初始连接请求是HTTP - 在 之后,服务器只是代理建立的TCP连接。

你可以在HTTP Tunneling wiki页面阅读更多关于它的信息。要看到这个动作,你可以开始一个netcat的服务器,并设置Firefox的代理指向端口:

nc -l 8000 

现在在Firefox型https://www.google.com,并检查NC输出:

CONNECT www.google.com:443 HTTP/1.1 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) 
Proxy-Connection: keep-alive 
Connection: keep-alive 
Host: www.google.com 

而这完全在明文。下图演示了Firefox代理期望通信。

enter image description here

相关问题