在Java

时间:2016-08-05 21:36:12

标签: java http ssl okhttp3

我目前正在为REST API编写包装器。该网站的SSL通过cloudflare计划。 我试图用OkHttp3调用api,这里的问题是cloudflare显然使用了一些旧的密码,Java默认禁用(在java.security中)。

当我尝试向api发出POST请求时,我得到了这个堆栈跟踪:

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 sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:241)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:198)
at okhttp3.internal.connection.RealConnection.buildConnection(RealConnection.java:174)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:114)
at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:193)
at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:129)
at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:98)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:109)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:124)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:170)
at okhttp3.RealCall.execute(RealCall.java:60)
at de.dootdoot.dubtrack4k.requesttypes.AbstractRequest.request(AbstractRequest.kt:28)
at de.dootdoot.dubtrack4k.requesttypes.AbstractRequest.request(AbstractRequest.kt:23)
at de.dootdoot.dubtrack4k.HttpRequester.post(HttpRequester.kt:26)
at de.dootdoot.dubtrack4k.HttpRequester.request(HttpRequester.kt:14)
at de.dootdoot.dubtrack4k.HttpRequester.request$default(HttpRequester.kt:11)
at de.dootdoot.dubtrack4k.requests.LoginRequest.setURL(LoginRequest.kt:50)
at de.dootdoot.dubtrack4k.requests.LoginRequest.request(LoginRequest.kt:17)
at de.dootdoot.dubtrack4k.models.Account.login(Account.kt:10)
at de.dootdoot.dubtrack4k.Dubtrack.login(Dubtrack.kt:19)
at LoginTest.loginTest(LoginTest.kt:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
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:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
... 65 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:146)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 71 more

所以我一直在四处寻找并找到了启用SSL调试的方法。 这导致了这个调试日志(Hastebin因为某些原因它不会进入代码块):

http://hastebin.com/palomijisa.dos

接近日志的末尾,它说:

%% Invalidated:  [Session-1, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
main, SEND TLSv1.2 ALERT:  fatal, description = certificate_unknown

这让我更多地谷歌了。显然,这是一个默认禁用的旧式密码套件,我可以确认,它列在java.security的禁用算法部分中。 现在,当我编写API包装器时,在我的机器上进行编辑是没有意义的,因为它不允许其他人使用它。 所以现在我的问题是,是否有一种方法可以允许该证书仅用于包装器所在的会话? 我已经看了一下OkHttp3,确实密码套件列在他们的CipherSuite课程中,但我不知道如何使用它。 有没有人有这种情况的经验? 提前谢谢!

1 个答案:

答案 0 :(得分:1)

问题是您的JVM不信任StartCom作为根CA,因此证书被拒绝。

证书由

签署

主题:CN = StartCom Class 2 IV服务器CA,OU = StartCom证书颁发机构,O = StartCom Ltd.,C = IL

这是调试日志中的错误

main, SEND TLSv1.2 ALERT:  fatal, description = certificate_unknown

手动下载https://aia.startssl.com/certs/ca.crt

您可以将其永久导入此JVM实例。它应该是安全的,因为chrome和OSX已经支持它了。

https://www.ailis.de/~k/uploads/scripts/import-startssl

keytool -keystore C:\Program Files\Java\jdk1.8.0_73\jre\lib\security\cacerts -storepass changeit -import -trustcacerts -alias startcom -file ca.crt

或者将证书与程序打包并在运行时加载。这将是我建议的路线。

https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java

https://github.com/yschimke/oksocial/blob/master/src/main/java/com/baulsupp/oksocial/security/CertificateUtils.java