2016-08-05 36 views
0

Ich schreibe gerade einen Wrapper für eine REST-API. Die Website hat ihre SSL durch einen Cloudflare-Plan gehen. Ich versuche mit okHttp3 meine Aufrufe an die API zu machen, das Problem hier ist, dass Cloudflare anscheinend einige alte Verschlüsselungen verwendet, die Java standardmäßig deaktiviert hat (in java.security).Alte/unsichere Ciphers programmgesteuert in Java aktivieren

Wenn ich versuche, eine POST-Anfrage an die api ich diesen Stacktrace erhalten zu machen:

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 

So fand ich habe um ein wenig suchen und einen Weg SSL-Debugging zu ermöglichen. Diese führte in diesem Debug-Protokoll (Hastebin, weil es nicht in einen Codeblock aus irgendeinem Grund gehen):

http://hastebin.com/palomijisa.dos

Nahe dem Ende der es log sagt dies:

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

Das hat mich dazu gebracht, noch etwas herum zu googeln. Anscheinend ist dies eine altmodische Ciphersuite, die standardmäßig deaktiviert ist, was ich bestätigen konnte. Sie ist im Abschnitt "Deaktivierte Algorithmen" von java.security aufgelistet. Jetzt, da ich einen API Wrapper schreibe, würde es keinen Sinn machen, dies auf meinem Rechner zu bearbeiten, da es niemandem sonst erlauben würde, es zu benutzen. Also meine Frage ist, gibt es eine Möglichkeit, das Zertifikat nur für die Sitzung, in der der Wrapper ist in? Ich habe mich ein wenig um OkHttp3 gekümmert und in der Tat ist diese Ciphersuite in ihrer CipherSuite Klasse aufgeführt, aber ich weiß nicht, wie ich das verwenden würde. Hat jemand Erfahrung mit dieser Art von Szenario? Vielen Dank im Voraus!

+0

Das sieht sehr seltsam. Ich hatte nie Probleme mit CloudFlare-Zertifikaten, und ich bin sehr skeptisch, dass sie inkompatibel sein würden. – chrylis

+0

Dies geschieht sowohl mit meinem eigenen API-Wrapper als auch mit einem bereits vorhandenen namens Dubtrack4J (verwendet auch OkHttp3). Dies geschah erst, nachdem sie CloudFlare SSL hinzugefügt hatten. Die URL, auf die ich schreiben möchte, ist https: //api.dubtrack.fm/auth/dubtrack' für den Fall, dass Sie es selbst testen möchten. –

Antwort

0

Das Problem ist, dass Ihre JVM StartCom nicht als Stammzertifizierungsstelle vertraut, daher wird das Zertifikat zurückgewiesen.

Das Zertifikat ist unterzeichnet von

Betreff: CN = StartCom Klasse 2 IV Server CA, OU = StartCom Zertifizierungsstelle, O = StartCom Ltd., C = IL

Dies ist der Fehler in der Debug log

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

herunterladen https://aia.startssl.com/certs/ca.crteinmal manuell

Sie entweder importieren kann es zul an dieser JVM-Instanz. Es sollte sicher sein, da Chrome und OSX es bereits unterstützen.

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 

Oder alternativ das Zertifikat mit Ihrem Programm verpacken und zur Laufzeit laden. Dies wäre meine vorgeschlagene Route.

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

+0

Das scheint also der richtige Ansatz zu sein. Ich lade jetzt das Zertifikat automatisch herunter und rufe Keytools Hauptmethode direkt mit den Parametern auf. Das Problem, vor dem ich jetzt stehe, ist, dass es eine Bestätigung durch die Konsole erwartet, haben Sie eine Idee, wie ich das automatisieren könnte? Ich habe bereits versucht, den Standard-Eingabestream durch einen ByteInputStream zu ersetzen, der nicht zu funktionieren schien. –

+0

Sie sollten dieses Bit nicht automatisieren, es vereitelt den Zweck der Sicherheitsmechanismen. Ich habe einige Links zu der Antwort hinzugefügt, die zeigt, wie man das Cert aus einer Datei lädt und es nur für Ihren Client verwendet. –

+0

Yup, hat es geschafft, mein Problem dank dieser Beispiele zu lösen. Vielen Dank! –