Ich habe zwei Spring-basierte Web-Apps A und B auf zwei verschiedenen Computern.
Ich möchte einen https-Anruf von Web-App A zu Web-App B tätigen, verwende jedoch ein selbstsigniertes Zertifikat in Computer B. Daher schlägt meine HTTPS-Anforderung fehl.
Wie kann ich die Validierung von https-Zertifikaten deaktivieren, wenn ich RestTemplate in Spring verwende? Ich möchte die Validierung deaktivieren, da sich sowohl die Webanwendung A als auch B innerhalb des internen Netzwerks befinden, die Datenübertragung jedoch über HTTPS erfolgen muss
spring
validation
ssl-certificate
resttemplate
Prabhu R.
quelle
quelle
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
@Bean public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true; SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom() .loadTrustMaterial(null, acceptingTrustStrategy) .build(); SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(csf) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); return restTemplate; }
quelle
Im Wesentlichen müssen Sie eine benutzerdefinierte TrustStrategy verwenden, die allen Zertifikaten vertraut , und NoopHostnameVerifier () verwenden , um die Überprüfung des Hostnamens zu deaktivieren. Hier ist der Code mit allen relevanten Importen:
import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; public RestTemplate getRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { TrustStrategy acceptingTrustStrategy = new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { return true; } }; SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier()); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); return restTemplate; }
quelle
NoopHostnameVerifier
ist sehr wichtig - andere Antworten vernachlässigen dies. Ein Anwendungsfall ist die Verwendung Ihres öffentlichen SSL-Zertifikats per Loopback anlocalhost
.Fügen Sie meine Antwort mit Cookie hinzu:
public static void main(String[] args) { MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("username", testUser); params.add("password", testPass); NullHostnameVerifier verifier = new NullHostnameVerifier(); MySimpleClientHttpRequestFactory requestFactory = new MySimpleClientHttpRequestFactory(verifier , rememberMeCookie); ResponseEntity<String> response = restTemplate.postForEntity(appUrl + "/login", params, String.class); HttpHeaders headers = response.getHeaders(); String cookieResponse = headers.getFirst("Set-Cookie"); String[] cookieParts = cookieResponse.split(";"); rememberMeCookie = cookieParts[0]; cookie.setCookie(rememberMeCookie); requestFactory = new MySimpleClientHttpRequestFactory(verifier,cookie.getCookie()); restTemplate.setRequestFactory(requestFactory); } public class MySimpleClientHttpRequestFactory extends SimpleClientHttpRequestFactory { private final HostnameVerifier verifier; private final String cookie; public MySimpleClientHttpRequestFactory(HostnameVerifier verifier ,String cookie) { this.verifier = verifier; this.cookie = cookie; } @Override protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException { if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection) connection).setHostnameVerifier(verifier); ((HttpsURLConnection) connection).setSSLSocketFactory(trustSelfSignedSSL().getSocketFactory()); ((HttpsURLConnection) connection).setAllowUserInteraction(true); String rememberMeCookie = cookie == null ? "" : cookie; ((HttpsURLConnection) connection).setRequestProperty("Cookie", rememberMeCookie); } super.prepareConnection(connection, httpMethod); } public SSLContext trustSelfSignedSSL() { try { SSLContext ctx = SSLContext.getInstance("TLS"); X509TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { } public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; ctx.init(null, new TrustManager[] { tm }, null); SSLContext.setDefault(ctx); return ctx; } catch (Exception ex) { ex.printStackTrace(); } return null; } } public class NullHostnameVerifier implements HostnameVerifier { public boolean verify(String hostname, SSLSession session) { return true; } }
quelle
Vollständiger Code zum Deaktivieren der Überprüfung des SSL-Hostnamens,
RestTemplate restTemplate = new RestTemplate(); //to disable ssl hostname verifier restTemplate.setRequestFactory(new SimpleClientHttpRequestFactory() { @Override protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException { if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection) connection).setHostnameVerifier(new NoopHostnameVerifier()); } super.prepareConnection(connection, httpMethod); } });
quelle
NoopHostnameVerifier
sollte nicht notwendig sein. Stellen Sie einfach eine (einfache) benutzerdefinierte Implementierung von bereit,HostnameVerifier
wie in anderen Antworten gezeigt. Dies kann sogar ein Lambda sein wie :(hostname, session) -> true
.Sie können dies mit der HTTPClient-API verwenden.
public RestTemplate getRestTemplateBypassingHostNameVerifcation() { CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); return new RestTemplate(requestFactory); }
quelle
Ich habe einen einfachen Weg gefunden
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true; SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory);
quelle
Um die Standardstrategie zu überschreiben, können Sie eine einfache Methode in der Klasse erstellen, in der Sie Ihre restTemplate verkabelt haben:
protected void acceptEveryCertificate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { TrustStrategy acceptingTrustStrategy = new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { return true; } }; restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory( HttpClientBuilder .create() .setSSLContext(SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build()) .build())); }
Hinweis: Sicherlich müssen Sie Ausnahmen behandeln, da diese Methode sie nur weiter wirft!
quelle
RestTemplateBuilder
innerhalb eines@Configuration
. Plus: - Anstelle der verschachtelten Klasse habe ich dieTrustAllStrategy
Sicherheit: Deaktivieren Sie die Prüfung des Hostnamens des https / TLS-Zertifikats. Der folgende Code wurde in der Spring Boot Rest-Vorlage verwendet
*HttpsURLConnection.setDefaultHostnameVerifier( //SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER // * @deprecated (4.4) Use {@link org.apache.http.conn.ssl.NoopHostnameVerifier} new NoopHostnameVerifier() );*
quelle
Bei diesem Problem handelt es sich um eine SSL-Verbindung. Wenn Sie versuchen, eine Verbindung zu einer Ressource herzustellen, muss das https-Protokoll eine gesicherte Verbindung herstellen. Das bedeutet, dass nur Ihr Browser und Ihr Website-Server wissen, welche Daten in Anforderungskörpern gesendet werden. Diese Sicherheit wird durch SSL-Zertifikate erreicht, die auf der Website gespeichert sind und von Ihrem Browser (oder einem anderen Client, in unserem Fall Spring RestTemplate mit Apache Http Client) mit der ersten Verbindung zum Host heruntergeladen werden. Es gibt RSA256-Verschlüsselung und viele andere coole Dinge. Aber am Ende eines Tages: Falls das Zertifikat nicht registriert oder ungültig ist, wird ein Zertifikatfehler angezeigt (die HTTPS-Verbindung ist nicht sicher). Um einen Zertifikatfehler zu beheben, muss der Website-Anbieter ihn für eine bestimmte Website kaufen oder irgendwie reparieren, z. B. https://www.register.com/ssl-certificates
Richtig, wie das Problem gelöst werden kann
Kein richtiger Weg, wie ein Problem gelöst werden kann
SSL-Zertifikat in Java-Cacerts importieren (Zertifikatspeicher)
keytool -importcert -trustcacerts -noprompt -storepass changeit -alias citrix -keystore "C: \ Programme \ Java \ jdk-11.0.2 \ lib \ security \ cacerts" -Datei citrix.cer
Schmutzige (unsichere) Art und Weise, wie das Problem gelöst werden kann
Lassen Sie RestTemplate die SSL-Überprüfung ignorieren
@Bean public RestTemplateBuilder restTemplateBuilder(@Autowired SSLContext sslContext) { return new RestTemplateBuilder() { @Override public ClientHttpRequestFactory buildRequestFactory() { return new HttpComponentsClientHttpRequestFactory( HttpClients.custom().setSSLSocketFactory( new SSLConnectionSocketFactory(sslContext , NoopHostnameVerifier.INSTANCE)).build()); } }; } @Bean public SSLContext insecureSslContext() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { return SSLContexts.custom() .loadTrustMaterial(null, (x509Certificates, s) -> true) .build(); }
quelle
Wenn Sie eine Ruhevorlage verwenden, können Sie diesen Code verwenden
fun getClientHttpRequestFactory(): ClientHttpRequestFactory { val timeout = envTimeout.toInt() val config = RequestConfig.custom() .setConnectTimeout(timeout) .setConnectionRequestTimeout(timeout) .setSocketTimeout(timeout) .build() val acceptingTrustStrategy = TrustStrategy { chain: Array<X509Certificate?>?, authType: String? -> true } val sslContext: SSLContext = SSLContexts.custom() .loadTrustMaterial(null, acceptingTrustStrategy) .build() val csf = SSLConnectionSocketFactory(sslContext) val client = HttpClientBuilder .create() .setDefaultRequestConfig(config) .setSSLSocketFactory(csf) .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build() return HttpComponentsClientHttpRequestFactory(client) } @Bean fun getRestTemplate(): RestTemplate { return RestTemplate(getClientHttpRequestFactory()) }
quelle
Java-Codebeispiel für HttpClient> 4.3
package com.example.teocodownloader; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; public class Example { public static void main(String[] args) { CloseableHttpClient httpClient = HttpClients.custom() .setSSLHostnameVerifier(new NoopHostnameVerifier()) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); } }
Vergessen Sie übrigens nicht, der POM-Datei die folgenden Abhängigkeiten hinzuzufügen:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency>
Sie können auch ein Java-Codebeispiel für HttpClient <4.3 finden .
quelle