天天看點

HTTPS(三)之JAVA 不校驗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憑證頒發過程。

本文系轉載博文,作者資訊如下:

作者:雪落孤村

連結:https://www.jianshu.com/p/ea07a32ec85d