【问题标题】:HTTPS Connections with Proxy cause SSLHandshakeException与代理的 HTTPS 连接导致 SSLHandshakeException
【发布时间】:2014-02-26 14:24:00
【问题描述】:

我已经为这个问题苦苦挣扎了几天,似乎找不到有用的答案...

我有一些软件,每次我想将它与代理服务器一起使用时都会导致 SSLHandshakeExceptions。我已经能够使用以下代码复制该问题(这比实际应用程序简单得多):

    HttpsURLConnection con = (HttpsURLConnection) new URL("https://www.google.com").openConnection();
    try {
        con.connect();
    } catch(Exception e) {
        e.printStackTrace();
    }

如果我运行此代码连接到 WiFi 热点(不需要代理服务器),我会得到连接并且一切都按预期工作:

java -cp . SampleJavaURLTest

但是,如果我使用代理服务器运行相同的 Java 命令:

java -cp . -DproxySet=true -DproxyHost={myProxyHost} -DproxyPort={myProxyPort} SampleJavaURLTest

我收到此异常(使用代码片段中的e.printStackTrace() 打印以使行号无关紧要:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
at SampleJavaURLTest.main(SampleJavaURLTest.java:116)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:323)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185)
... 11 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
... 17 more

因此,第一个合乎逻辑的建议是“使用 InstallCert 程序并添加 google 的证书”。但这不是问题,不知何故 Java 不喜欢通过代理服务器处理证书的方式。

我使用完全相同的 JVM 运行这两个示例,除了命令行中的代理设置之外没有进一步的配置更改。事实上,这两个测试都是使用同一个控制台窗口完成的,两个测试之间只需要几秒钟就可以切换网络......这是一个 java -v 打印输出:

java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) Client VM (build 20.5-b03, mixed mode, sharing)

而且,100% 确定,我还使用更新的 JVM 进行了测试:

java version "1.7.0_10"
Java(TM) SE Runtime Environment (build 1.7.0_10-b18)
Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode)

作为一种解决方法,我使用这种方法禁用了所有证书验证:

http://code.google.com/p/misc-utils/wiki/JavaHttpsUrl

虽然它并没有真正影响到我,而且我可以接受这种解决方法(如果有人用虚假证书在通信中进行黑客攻击,这不是那么重要),我真的很想知道如何正确地让证书正常工作应该。我错过了什么?

【问题讨论】:

  • 对不起,但正如我解释的那样,我已经这样做了,没有代理服务器,ssl 连接也可以正常工作。我错过了什么?
  • 试试-Dhttps.proxyHost=...https.proxyPort=...,还有-Djavax.net.debug=ssl,handshake,把失败前的部分贴在这里,特别是最初的ClientHelloCertificate消息。

标签: java ssl proxy


【解决方案1】:

如果我理解正确,您的 SSL 连接在没有代理的情况下成功,如果您禁用证书验证,也可以通过代理成功,但如果您启用证书验证,则使用代理失败。在这种情况下,代理正在篡改 SSL,例如它进行中间人攻击(在某些防火墙中也称为 SSL 拦截或 squid 中的 SSL 碰撞)。如果这不是攻击,而是此代理的已知功能(例如扫描 SSL 连接以查找病毒等),您需要导入代理拦截 CA,因为由于中间人,您不再说话SSL 到 Web 服务器,但到代理,然后代理与服务器进行 SSL 通信。

【讨论】:

  • 嗯,这个答案对我来说听起来不错。它是一个公司代理,所以我确信它不是“攻击”,但拦截 CA 对我来说似乎是合理的。问题是我无法使用 InstallCert,因为它创建了代理设置未检测到的“本机”ssl 套接字。有没有办法使 InstallCert 程序能够通过代理进行连接?或者,还有其他方法吗?
  • 我不知道 InstallCert 但如果您可以使用普通 Web 浏览器通过代理连接,则浏览器/系统证书存储中应该有所需的代理 CA,您应该能够导出它.我对 Java 证书管理知之甚少,不知道如何安装它然后在 Java 中使用。
  • 好的,谢谢。我刚刚检查了google.com 的证书,它不是由谷歌颁发的,而是由托管代理服务器的公司颁发的,所以这证实了你的答案是正确的,现在它很有意义......跨度>
猜你喜欢
  • 1970-01-01
  • 2015-06-05
  • 2023-03-03
  • 2016-09-20
  • 1970-01-01
  • 1970-01-01
  • 2018-12-01
  • 1970-01-01
  • 2016-07-12
相关资源
最近更新 更多