Java - 使用handshake_failure从EC2实例进行HTTPS GET调用失败,在本地运行

时间:2016-08-29 00:56:05

标签: java ssl amazon-ec2 https

我的想法已经不多了,这就是我在这里寻求帮助的原因。我有一个通过HTTPS进行REST调用的小类。我正在进行某种抓取,并希望尽可能避免安装所有SSL证书。

代码在本地运行良好(来自Eclipse和独立的Tomcat),但每次从我的AWS EC2实例运行时都会失败javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

代码是:

// 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();
    }
}

我也尝试了基本版本(没有任何覆盖SSLFactory方法),但无济于事。

另外,我没有设法从Tomcat上的javax.net.debug获取日志(既不在远程也不在本地),所以如果您有任何想法,这也可能非常有用。

如果我能提供更多信息,请告诉我,非常感谢您的帮助!

塞巴斯蒂安

2 个答案:

答案 0 :(得分:2)

握手失败可能是由许多不同原因引起的,例如错误的Java版本,服务器设置,设置主机名验证程序(无论如何都是坏主意),SNI ......这个问题中的当前信息不足以确定问题是什么。

查看服务器的SSLLabs report时,两个信息看起来很有趣:

  • 服务器需要SNI。
  • 服务器仅支持ECDHE密码。

如果您设置了主机名验证程序,那么第一个可能是旧Java版本的问题,甚至是JDK8的问题(虽然这对于此站点不是必需的,但您可以这样做。)

第二个可能是较旧的Java版本的问题,或者未安装无限强度的加密扩展。

答案 1 :(得分:0)

@ SteffenUlrich的回答让我走上了正确的轨道。问题确实是因为在开放的jdk 7中不支持ECDHE密码。我迁移到Oracle的JDK 8,现在情况正常。