Allow insecure HTTPS connection for Java JDK 11 HttpClient

前端 未结 2 1184
生来不讨喜
生来不讨喜 2020-12-09 10:40

Sometimes it is needed to allow insecure HTTPS connections, e.g. in some web-crawling applications which should work with any site. I used one such solution with old HttpsUR

相关标签:
2条回答
  • 2020-12-09 10:59

    As suggested already you need an SSLContext which ignores the bad certificates. The exact code which obtains the SSLContext in one of the links in the question should work by basically creating a null TrustManager which doesn't look at the certs:

    private static TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            }
        }
    };
    
    public static  void main (String[] args) throws Exception {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts, new SecureRandom());
    
        HttpClient client = HttpClient.newBuilder()
            .sslContext(sslContext)
            .build();
    

    The problem with the above is obviously that server authentication is disabled completely for all sites. If there were only one bad certificate then you could import it into a keystore with:

    keytool -importcert -keystore keystorename -storepass pass -alias cert -file certfile
    

    and then initialize the SSLContext using an InputStream reading the keystore as follows:

    char[] passphrase = ..
    KeyStore ks = KeyStore.getInstance("PKCS12");
    ks.load(i, passphrase); // i is an InputStream reading the keystore
    
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
    kmf.init(ks, passphrase);
    
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
    tmf.init(ks);
    
    sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
    

    Either of the above solutions will work for a self-signed certificate. A third option is in the case where the server provides a valid, non self-signed certificate but for a host which does not match any of the names in the certificate it provides, then a system property "jdk.internal.httpclient.disableHostnameVerification" can be set to "true" and this will force the certificate to be accepted in the same way that the HostnameVerifier API was used previously. Note, that in normal deployments it isn't expected that any of these mechanisms would be used, as it should be possible to automatically verify the certificate supplied by any correctly configured HTTPS server.

    0 讨论(0)
  • 2020-12-09 11:02

    With Java 11, as well you can do a similar effort as mentioned in the selected answer in the link shared with the HttpClient built as:

    HttpClient httpClient = HttpClient.newBuilder()
            .connectTimeout(Duration.ofMillis(<timeoutInSeconds> * 1000))
            .sslContext(sc) // SSL context 'sc' initialised as earlier
            .sslParameters(parameters) // ssl parameters if overriden
            .build();
    

    with a sample request

    HttpRequest requestBuilder = HttpRequest.newBuilder()
                .uri(URI.create("https://www.example.com/getSomething"))
                .GET()
                .build();
    

    can be executed as:

    httpClient.send(requestBuilder, HttpResponse.BodyHandlers.ofString()); // sends the request
    

    Update from comments, to disable the hostname verification, currently one can use the system property:

    -Djdk.internal.httpclient.disableHostnameVerification
    

    which can be set programmatically as following :-

    final Properties props = System.getProperties(); 
    props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString());
    
    0 讨论(0)
提交回复
热议问题