Wie deaktiviere ich die SSL-Zertifikatsprüfung mit Spring RestTemplate?
Lesezeit: 13 Minuten
Schlitten
Ich versuche, einen Integrationstest zu schreiben, bei dem unser Test einen eingebetteten HTTPS-Server mit startet Einfach. ich erstellte ein selbstsigniertes Zertifikat mit keytool und kann über einen Browser auf den Server zugreifen (insbesondere Chrome, und ich erhalte eine Warnung über das selbstsignierte Zertifikat).
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://localhost:8088":sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is 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 org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:557)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:444)
at net.initech.DummySslServer.shouldConnect(DummySslServer.java:119)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
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.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
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:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: 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:1917)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:301)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:295)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1369)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:860)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)
at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:52)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:541)
... 33 more
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:1351)
... 47 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:145)
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)
... 53 more
Aus anderen Fragen u bloggenBeiträge Ich habe den Rat gesehen, das zu ersetzen HostnameVerifier mit sowas
Trotzdem erhalte ich immer noch den oben genannten Fehler. Wie kann ich es umgehen?
Zertifikat lokal installieren außen des Unit-Tests ist nicht eine Option, da es dann manuell auf jeder Entwicklungsmaschine und jedem Build-Server installiert werden müsste und eine Lawine von Bürokratie verursachen würde.
Wir brauchen SSL, da wir eine Bibliothek testen, die darauf sitzt RestTemplate und dass wir es richtig konfigurieren.
Ich verwende Java 8 (könnte aber 7 verwenden) und Spring 4.0.3 .
Sie müssen den HTTP-Connector, den die Vorlage verwendet, manuell konfigurieren.
– chrylis -vorsichtig optimistisch-
7. Mai 2014 um 2:27 Uhr
@chrylis Ich sehe keine Klasse des Namens HttpConnector entweder in Javas SDK oder Springs JavaDoc. Welche Klasse meinst du konkret?
– Schlitten
7. Mai 2014 um 13:56 Uhr
Hast du meine Antwort überprüft [here][1]. Das funktioniert für mich. [1]: stackoverflow.com/questions/18476073/…
– Niles
10. Mai 2014 um 14:59 Uhr
Siehe auch stackoverflow.com/questions/859111/…
– Raedwald
9. Oktober 2014 um 14:17 Uhr
Sled, könnten Sie bitte bestätigen, wie Sie dieses Problem gelöst haben?
– PAA
7. Januar 2020 um 16:12 Uhr
Schlitten
Ich wünschte, ich hätte immer noch einen Link zu der Quelle, die mich in diese Richtung geführt hat, aber das ist der Code, der für mich funktioniert hat. Indem Sie über das JavaDoc nachsehen X509 TrustManager es sieht so aus wie die TrustManagers Arbeit besteht darin, bei erfolgreicher Validierung nichts zurückzugeben, andernfalls eine Ausnahme auszulösen. Also mit a Null-Implementierung, wird dies als erfolgreiche Validierung behandelt. Dann entfernen Sie alle anderen Implementierungen.
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.X509Certificate;
public final class SSLUtil{
private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers(){
return null;
}
public void checkClientTrusted( X509Certificate[] certs, String authType ){}
public void checkServerTrusted( X509Certificate[] certs, String authType ){}
}
};
public static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
// Install the all-trusting trust manager
final SSLContext sc = SSLContext.getInstance("SSL");
sc.init( null, UNQUESTIONING_TRUST_MANAGER, null );
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
// Return it to the initial state (discovered by reflection, now hardcoded)
SSLContext.getInstance("SSL").init( null, null, null );
}
private SSLUtil(){
throw new UnsupportedOperationException( "Do not instantiate libraries.");
}
}
@ArtB was ist die Collect-Nutzung für den Code? sollte ich jedes Mal SSLUtil.turnOffSslChecking() aufrufen, bevor ich die Rest-URL aufrufe? irgendein Codebeispiel bitte
– Junchen Liu
31. Mai 2017 um 9:21 Uhr
Es hängt von Ihrem Anwendungsfall ab. Aber ich empfehle, die Abzweigung in der @Before Methode in einem Komponententest und das Einschalten in der @After.
– Schlitten
31. Mai 2017 um 13:56 Uhr
In meinen Tests hat dies SSL-Prüfungen definitiv deaktiviert, aber die Methode turnOn () konnte die SSL-Prüfung nicht wiederherstellen. Ich habe eine inkrementelle Verbesserung in einer Antwort unten gepostet.
– Chrisinmtown
8. Oktober 2019 um 17:48 Uhr
Wie können wir dies mit RestTemplate verwenden?
– PAA
7. Januar 2020 um 16:16 Uhr
OhadR
Für andere Entwickler, die diese Frage finden und eine andere Lösung benötigen, die nicht nur für Unit-Tests geeignet ist:
Ich habe gefunden Dies auf einem Blog (nicht meine Lösung! Gutschrift an den Besitzer des Blogs).
Dies funktioniert in meiner Situation nicht, ich bekomme immer noch: javax.net.ssl.SSLHandshakeException: fatale Warnung erhalten: handshake_failure
– Matt Weiler
13. März 2019 um 14:22 Uhr
Bitte beachten Sie, dass diese Antwort davon ausgeht, dass Sie Ihre Spring-Umgebung, möglicherweise Spring-Boot, so konfiguriert haben, dass sie Apache HTTP Client als Implementierung verwendet, was NICHT die Standardeinstellung ist.
– Chrisinmtown
8. Oktober 2019 um 17:24 Uhr
Nach dieser Implementierung erhalte ich SSLPeerUnverifiedException. wie man das löst
– ojus kulkarni
24. Oktober 2019 um 3:16 Uhr
Ich habe den bereitgestellten Apache verwendet new TrustSelfSignedStrategy() in loadTrustMaterial, aber der Fehler wird immer noch angezeigt. Dann habe ich es durch ersetzt TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true; wie oben empfohlen, und es funktioniert jetzt gut!
– AP22
12. März 2020 um 23:05 Uhr
bei mir hat es funktioniert. Ich musste einen externen, im Internet gehosteten HTTPS-Endpunkt von meinem Tomcat 8.5 mit SpringBoot WAR aufrufen. Früher, als ich meine App über „mvn spring-boot:run“ ausführte, wurde der HTTPS-Endpunkt erfolgreich aufgerufen, aber beim Ausführen des WAR im Tomcat 8.5-Container konnte der HTTPS-Endpunkt nicht aufgerufen werden. erforderlich, um die folgende Abhängigkeit hinzuzufügen: org.apache.httpcomponentshttpclient4.5.1
– nirmalsingh
9. August 2021 um 9:47 Uhr
chrisinmtown
Unten finden Sie eine bescheidene Verbesserung des oben gezeigten Codes von @Sled. Bei dieser Turn-Back-On-Methode fehlte eine Zeile, jetzt besteht sie meine Tests. Dadurch wird das Spoofing von HTTPS-Zertifikaten und Hostnamen deaktiviert, wenn RestTemplate in einer Spring-Boot-Anwendung der Version 2 verwendet wird, die die Standard-HTTP-KonfigurationNICHT für die Verwendung von Apache HTTP Client konfiguriert.
package org.my.little.spring-boot-v2.app;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* Disables and enables certificate and host-name checking in
* HttpsURLConnection, the default JVM implementation of the HTTPS/TLS protocol.
* Has no effect on implementations such as Apache Http Client, Ok Http.
*/
public final class SSLUtils {
private static final HostnameVerifier jvmHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
private static final HostnameVerifier trivialHostnameVerifier = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
};
private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
public static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
HttpsURLConnection.setDefaultHostnameVerifier(trivialHostnameVerifier);
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, UNQUESTIONING_TRUST_MANAGER, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
HttpsURLConnection.setDefaultHostnameVerifier(jvmHostnameVerifier);
// Return it to the initial state (discovered by reflection, now hardcoded)
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, null, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
private SSLUtils() {
throw new UnsupportedOperationException("Do not instantiate libraries.");
}
}
Vielen Dank! Diese aktualisierte Lösung hat bei mir funktioniert. FYI Weitere Informationen zur Implementierung der Überprüfung des Hostnamens finden Sie in sun.net.www.protocol.https.HttpsClientDa ist ein riesiger Kommentarblock Angabe des verwendeten Algorithmus, der explizit eingestellt werden kann. Ich dachte ursprünglich, dass einfach nur die Standardeinstellung HostnameVerifier würde ausreichen, aber es ist nicht und ich denke, es liegt daran, dass der Standard-Algorithmus zur Überprüfung des Hostnamens verwendet wird.
– mikewang
8. Oktober 2019 um 17:54 Uhr
Das hat auch bei mir funktioniert. Ich habe es vor dem Start der Spring Boot-App in der Hauptmethode aufgerufen.
– Chrys007
21. August 2020 um 10:31 Uhr
Endlich! Eine Lösung, die tatsächlich funktioniert und nicht auf nicht vorhandenes Apache http oder andere nicht standardmäßige Konfigurationen angewiesen ist!
Sie können Ihren Schlüsselspeicher auch registrieren:
private void registerKeyStore(String keyStoreName) {
try {
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream keyStoreInputStream = classLoader.getResourceAsStream(keyStoreName);
if (keyStoreInputStream == null) {
throw new FileNotFoundException("Could not find file named '" + keyStoreName + "' in the CLASSPATH");
}
//load the keystore
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(keyStoreInputStream, null);
//add to known keystore
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keystore);
//default SSL connections are initialized with the keystore above
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustManagers, null);
SSLContext.setDefault(sc);
} catch (IOException | GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
Michael
Hier ist eine Lösung, bei der die Sicherheitsüberprüfung deaktiviert ist (z. B. Konversation mit dem localhost). Außerdem enthalten einige der Lösungen, die ich jetzt gesehen habe, veraltete Methoden und dergleichen.
Sie müssen den HTTP-Connector, den die Vorlage verwendet, manuell konfigurieren.
– chrylis -vorsichtig optimistisch-
7. Mai 2014 um 2:27 Uhr
@chrylis Ich sehe keine Klasse des Namens
HttpConnector
entweder in Javas SDK oder Springs JavaDoc. Welche Klasse meinst du konkret?– Schlitten
7. Mai 2014 um 13:56 Uhr
Hast du meine Antwort überprüft [here][1]. Das funktioniert für mich. [1]: stackoverflow.com/questions/18476073/…
– Niles
10. Mai 2014 um 14:59 Uhr
Siehe auch stackoverflow.com/questions/859111/…
– Raedwald
9. Oktober 2014 um 14:17 Uhr
Sled, könnten Sie bitte bestätigen, wie Sie dieses Problem gelöst haben?
– PAA
7. Januar 2020 um 16:12 Uhr