简体   繁体   中英

Java - HTTPS GET call fails from EC2 instance with handshake_failure, works locally

I'm running out of ideas, which is why I'm asking for help here. I have a small class that does a REST call over HTTPS. I'm doing some kind of scraping, and would like to avoid installing all SSL certificates if possible.

The code works well locally (both from Eclipse and a standalone Tomcat), but it fails with a javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure every time when running from my AWS EC2 instance.

Code is:

// apiUrl looks like https://hsreplay.net/api/v1/games/jdUbSjsEcBL5rCT7dgMXRn
private String restGetCall(String apiUrl) throws Exception {
    System.setProperty("javax.net.debug", "ALL");
    SSLContextBuilder builder = new SSLContextBuilder();
    builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(),
            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) {
        @Override
        protected void prepareSocket(SSLSocket socket) throws IOException {
            try {
                log.debug("************ setting socket HOST property *************");
                PropertyUtils.setProperty(socket, "host", "hsreplay.net");
                socket.setEnabledProtocols(new String[] { "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" });
            }
            catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
                log.error(ex.getMessage());
                slackNotifier.notifyError(ex);
            }
            super.prepareSocket(socket);
        }

    };
    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

    HttpGet httpGet = new HttpGet(apiUrl);
    CloseableHttpResponse response1 = httpClient.execute(httpGet);
    StringBuilder result = new StringBuilder();
    try {
        System.out.println(response1.getStatusLine());
        HttpEntity entity1 = response1.getEntity();
        BufferedReader rd = new BufferedReader(new InputStreamReader(entity1.getContent()));
        String line;
        while ((line = rd.readLine()) != null) {
            result.append(line);
        }
        // do something useful with the response body
        // and ensure it is fully consumed
        EntityUtils.consume(entity1);
    }
    finally {
        response1.close();
    }
}

I also tried the basic version (without any override of the SSLFactory methods), but to no avail.

Also, I don't manage to get the logs from javax.net.debug on Tomcat (neither on the remote nor on a local one), so if you have any idea here that could also be very useful.

Please let me know if I can provide more information, and thanks a lot for your help!

Sébastien

Handshake failures might be caused by lots of different reasons, like the wrong Java version, server settings, setting a hostname verifier (bad idea anyway), SNI ... . The current information in this question are not enough to say for sure what the problem is.

When looking at the SSLLabs report for the server two information look interesting:

  • The server needs SNI.
  • The server supports only ECDHE ciphers.

The first might be a problem with older Java versions or even with JDK8 if you set a hostname verifier (which you do although it would not be necessary for this site).

The second might be a problem with older Java version or if the cryptography extensions for unlimited strength are not installed.

@SteffenUlrich's answer put me on the correct rails. The issue was indeed because of the ECDHE ciphers that aren't supported in open jdk 7. I migrated to Oracle's JDK 8, and things are working fine now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM