【问题标题】:Implementing a Simple HTTPS Proxy Application with Java?用 Java 实现一个简单的 HTTPS 代理应用程序?
【发布时间】:2013-04-27 20:06:52
【问题描述】:

出于教育目的,我正在用 Java 编写一个简单的 HTTPS 代理程序。我的程序在端口(例如 7443)上侦听来自浏览器(例如 Firefox)的传入 HTTPS 请求,解析请求并将其转发到所需的目的地(例如 @987654321 @)。

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?

异常表示连接可以是纯文本的,但只有来自 Firefox 的 HTTPS 连接设置为使用此端口。我已经记录了 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

Firefox 正在谈论 palin-text,我认为 CONNECT 是一个 SOCKS 命令(不过我不确定),我没有在 Firefox 的 SOCKS 设置中设置任何内容。下面是火狐的代理设置截图:

我在这里错过了什么?!我需要做些什么才能使其与 Firefox 或任何其他浏览器一起使用?!

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

对于那些认为这是 another question 的副本并且已经在另一个问题中得到回答的人,我不得不说:是的,这两个问题都源于一个类似的问题,但引用问题中的唯一答案指向使用 SSL Sockets 被证明具有误导性并导致了这个新问题。因此,尽管他们针对的是类似的问题,但这个问题显示了解决问题的完全不同但误导性的路径,因此它可以为未来面临此类问题的人提供有用的指导。

【问题讨论】:

  • 这不是引用问题的重复。这两个问题明显不同,在引用的问题中没有可接受的解决方案。
  • 对于那些在这个线程中结束的人:您可能对 TheConstructor 的工作示例感兴趣:stackoverflow.com/questions/16351413/…

标签: java ssl https proxy jsse


【解决方案1】:

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

【讨论】:

  • 我不认为这是正确的......我之前尝试过这个解决方案,但它没有工作......你可以在stackoverflow.com/questions/14153662/…查看我之前关于这个解决方案的问题跨度>
  • 当然是正确的。请参阅 RFC。显然,浏览器正在以明文形式发送 CONNECT 命令,显然您可以推断出它期待以明文形式回复,并且显然,如果您在两个方向上传输所有其他字节,而无需进一步干预,那么任何剩余的问题都必须在服务器端或浏览器端。您需要比“它不起作用”更具体。您引用的另一个问题也没有提供任何进一步的信息。
  • 正如我所说,我已经完全按照您的建议进行了尝试,实际上这是我想到的第一个方法,但它失败了。正如我提供的另一个问题中提到的,将浏览器的CONNECT请求转发到服务器总是会导致connection reset错误,这意味着服务器没有响应并关闭连接......这种行为很明显,因为服务器正在 443 上侦听 SSL/TLS HELLO 消息,它收到了 CONNECT,这不是预期的 SSL/TLS 消息。
  • @SeyedMohammad,您的代理不应该转发CONNECT 请求,而是处理它,即建立与服务器的纯 TCP 连接并返回 200 OK。然后,您的代理服务器应该简单地中继客户端和服务器之间的流量。 SSL/TLS 层将位于此中继连接之上,但代理本身不参与其中。
  • 这正是我们俩一直在说的。没有人说要转发 CONNECT 命令。所以你根本没有“完全尝试这个”。而且不向我们展示代码,只是重复你已经“完全尝试过”是不好的。
【解决方案2】:

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

在这种机制中,客户端请求 HTTP 代理服务器转发 使用“CONNECT”HTTP 到所需目的地的 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 代理如何进行通信。

【讨论】:

    猜你喜欢
    • 2011-05-01
    • 2015-01-02
    • 2012-04-30
    • 1970-01-01
    • 2018-08-14
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    相关资源
    最近更新 更多