JAVA 不校验HTTPS服务器证书
2024-03-22 17:10 l_v_y_forever 阅读(415) 评论(0) 编辑 收藏 举报转载自:https://www.jianshu.com/p/ea07a32ec85d
本章是HTTPS那些事儿的第三篇文章,其他相关文章请参见:前言
本篇主要描述JAVA经常遇到的场景:不校验服务器CA证书。主要包含以下内容:
- HttpsURLConnection不校验服务器CA证书
- Spring RestTemplate不校验服务器CA证书
* 注意
本文纯手工打造,转载请注明出处。
HttpsURLConnection不校验服务器CA证书
有些情况下,虽然服务器端使用的是https协议,但是其证书不是由权威机构颁发的,客户端如果使用jdk默认的证书会校验失败。为了在项目初期进行调试,我们可以忽略服务器证书校验。由前一篇文章可知,要达到不校验服务器证书的目的,必须将hostname校验和CA证书校验同时关闭。
要忽略hostname校验,可以通过前一篇文章JAVA中HTTPS那些事儿中的HostnameVerifier小节介绍的case4场景来实现。要忽略证书校验,则需要自定义SSLSocketFactory。整体代码如下:
public void ignore() throws NoSuchAlgorithmException, KeyManagementException {
// 自定义证书校验器
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates,
String s) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates,
String s) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// 自定义hostname校验器
HostnameVerifier allHostsValid = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
从代码中可以看到setDefaultSSLSocketFactory和setDefaultHostnameVerifier都是HttpsURLConnection的静态方法,也就是此处的设置是全局的。所以在进行实际的HTTPS访问前,调用一次ignore方法,即可在后续所有的HTTPS访问中达到不校验服务器CA证书的目的。
Spring RestTemplate不校验服务器CA证书
Spring中的RestTemplate是用于访问Restful服务的便捷工具类,该类依靠更下层的组件来完成网络请求。默认使用JDK中的HttpURLConnection,同时支持配置Apache HttpComponents HttpClient(4.3+)、OkHttp(2.x and 3.x)、Netty4。所以要使RestTemplate在访问HTTPS服务时忽略证书校验,其实需要配置的是底层的实现组件。
- 如果使用默认实现HttpURLConnection,如果要忽略证书只需要按照前一小节HttpsURLConnection不校验服务器CA证书进行操作即可。
- Apache HttpComponents HttpClient(4.3+)不校验CA证书
Apache的HttpClient也是依赖于标准的java加密(Java Cryptography-JCE)和安全socket扩展(Secure Sockets-JSEE),所以需要忽略证书同样需要创建一个javax.net.ssl.SSLContext。与HttpsURLConnection一样Apache HttpClient提供可选的HostnameVerifier功能,并提供两个实现类DefaultHostnameVerifier和NoopHostnameVerifier,第一个采用RFC 2818规则校验hostname,第二个则不进行校验。如果需要不校验服务器CA证书,Apache HttpClient提供了一个帮助了可以直接使用,代码如下:
public static void main(String[] args) throws IOException, KeyStoreException,
NoSuchAlgorithmException, KeyManagementException {
// 配置Apache HttpClient
HttpClient httpClient = HttpClients
.custom()
.setSSLContext(
new SSLContextBuilder()
.loadTrustMaterial(null, TrustAllStrategy.INSTANCE)
.build()
)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
// 让RestTemplate使用Apache HttpClient访问网络
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
String resp = restTemplate.getForObject(IgnoreServerCerts.testUrl,
String.class);
System.out.println(resp);
}
- 其他
RestTemplate同时支持使用OkHttp(2.x and 3.x)和Netty4,但是由于项目中暂未所用,我对这些组件也不熟悉,如果有使用到可以自行研究。
总结
本篇文章主要介绍的是java中怎么实现不校验HTTPS服务器证书,主要介绍JDK中的HttpURLConnection和Apache HttpComponents HttpClient(4.3+)怎么忽略。同时明确Spring的RestTemplate是依赖于底层网络访问组件实现的Http访问,要忽略证书只需要配置底层组件即可。
至此,本系列文章主要部分已技术,还有最后一篇可供选择阅读使用keytool模拟CA证书颁发过程。