本篇主要描述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憑證頒發過程。
本文系轉載博文,作者資訊如下:
作者:雪落孤村
連結:https://www.jianshu.com/p/ea07a32ec85d