在 Spring RestTemplate 中禁用 SSL 证书验证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4072585/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Disabling SSL Certificate Validation in Spring RestTemplate
提问by Prabhu R
I am having two Spring based web apps A and B, on two different machines.
我在两台不同的机器上有两个基于 Spring 的 Web 应用程序 A 和 B。
I want to make a https call from web app A to web app B, however I am using a self-signed certificate in Machine B. So my HTTPS request fails.
我想从 Web 应用程序 A 向 Web 应用程序 B 进行 https 调用,但是我在机器 B 中使用了自签名证书。所以我的 HTTPS 请求失败了。
How can I disable https certificate validation when using RestTemplate in Spring ? I want to disable validation because both web app A and B are within the internal network, but data transfer has to happen over HTTPS
在 Spring 中使用 RestTemplate 时如何禁用 https 证书验证?我想禁用验证,因为 Web 应用程序 A 和 B 都在内部网络中,但数据传输必须通过 HTTPS 进行
采纳答案by Raghuram
What you need to add is a custom HostnameVerifierclass bypasses certificate verification and returns true
您需要添加的是一个自定义HostnameVerifier类绕过证书验证并返回 true
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
This needs to be placed appropriately in your code.
这需要适当地放置在您的代码中。
回答by DanieleDM
@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;
}
回答by rouble
Essentially two things you need to do are use a custom TrustStrategy that trusts all certs, and also use NoopHostnameVerifier()to disable hostname verification. Here is the code, with all the relevant imports:
基本上你需要做的两件事是使用信任所有证书的自定义 TrustStrategy,并使用NoopHostnameVerifier()禁用主机名验证。这是代码,包含所有相关的导入:
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;
}
回答by Ran Adler
Add my response with cookie :
用 cookie 添加我的回复:
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;
}
}
回答by Amit Parashar
You can use this with HTTPClient API.
您可以将其与 HTTPClient API 一起使用。
public RestTemplate getRestTemplateBypassingHostNameVerifcation() {
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}
回答by user1986251
Complete code to disable SSL hostname verifier,
禁用 SSL 主机名验证器的完整代码,
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);
}
});
回答by sagaris
To overrule the default strategy you can create a simple method in the class where you are wired your restTemplate:
要推翻默认策略,您可以在连接 restTemplate 的类中创建一个简单的方法:
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()));
}
Note: Surely you need to handle exceptions since this method only throws them further!
注意:当然你需要处理异常,因为这个方法只会进一步抛出它们!
回答by Sats
Security: disable https/TLS certificate hostname check,the following code worked in spring boot rest template
安全性:禁用 https/TLS 证书主机名检查,以下代码适用于 spring boot rest 模板
*HttpsURLConnection.setDefaultHostnameVerifier(
//SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
// * @deprecated (4.4) Use {@link org.apache.http.conn.ssl.NoopHostnameVerifier}
new NoopHostnameVerifier()
);*
回答by Yash Jagdale
I found a simple way
我找到了一个简单的方法
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);
回答by Oleg Maksymuk
This problem is about SSL connection. When you try to connect to some resource https protocol requires to create secured connection. That means only your browser and website server know what data is being sent in requests bodies. This security is achieved by ssl certificates that stored on website and are being downloaded by your browser (or any other client, Spring RestTemplate with Apache Http Client behind in our case) with first connection to host. There are RSA256 encryption and many other cool things around. But in the end of a day: In case certificate is not registered or is invalid you will see certificate error (HTTPS connection is not secure). To fix certificate error website provider need to buy it for particular website or fix somehow e.g. https://www.register.com/ssl-certificates
这个问题是关于 SSL 连接的。当您尝试连接到某些资源时,https 协议需要创建安全连接。这意味着只有您的浏览器和网站服务器知道在请求正文中发送了哪些数据。这种安全性是通过存储在网站上的 ssl 证书实现的,并且正在由您的浏览器(或任何其他客户端,在我们的案例中,带有 Apache Http 客户端的 Spring RestTemplate)在第一次连接到主机时下载。周围有 RSA256 加密和许多其他很酷的东西。但归根结底:如果证书未注册或无效,您将看到证书错误(HTTPS 连接不安全)。要修复证书错误网站提供商需要为特定网站购买或以某种方式修复例如https://www.register.com/ssl-certificates
Right way how problem can be solved
解决问题的正确方法
- Register SSL certificate
- 注册 SSL 证书
Not a right way how problem can be solved
解决问题的方法不对
- download broken SSL certificate from website
import SSL certificate to Java cacerts (certificate storage)
keytool -importcert -trustcacerts -noprompt -storepass changeit -alias citrix -keystore "C:\Program Files\Java\jdk-11.0.2\lib\security\cacerts" -file citrix.cer
- 从网站下载损坏的 SSL 证书
将 SSL 证书导入 Java cacerts(证书存储)
keytool -importcert -trustcacerts -noprompt -storepass changeit -alias citrix -keystore "C:\Program Files\Java\jdk-11.0.2\lib\security\cacerts" -file citrix.cer
Dirty (Insecure) way how problem can be solved
肮脏(不安全)方式如何解决问题
make RestTemplate to ignore SSL verification
@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(); }
使 RestTemplate 忽略 SSL 验证
@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(); }

