【发布时间】: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,把失败前的部分贴在这里,特别是最初的ClientHello和Certificate消息。