Java-HTTPS GET调用从EC2实例失败,握手失败,在本地工作

Java-HTTPS GET调用从EC2实例失败,握手失败,在本地工作,java,ssl,amazon-ec2,https,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.

我的想法快用完了,这就是为什么我在这里寻求帮助。我有一个通过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
获取日志(既不在远程也不在本地),因此,如果您对此有任何想法,这也可能非常有用

请让我知道,如果我可以提供更多的信息,并感谢您的帮助很多


Sébastien

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

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

  • 服务器需要SNI
  • 服务器仅支持ECDHE密码
第一个问题可能是旧Java版本的问题,甚至是JDK8的问题,如果您设置了主机名验证器(尽管此站点不需要这样做)


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

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

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

  • 服务器需要SNI
  • 服务器仅支持ECDHE密码
第一个问题可能是旧Java版本的问题,甚至是JDK8的问题,如果您设置了主机名验证器(尽管此站点不需要这样做)


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

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

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

你看到了吗?握手失败有许多不同的原因,但使用最新的信任存储,您似乎应该能够在不安装特定证书的情况下实现这一点。它似乎是CloudFlare的ECC证书,所以我认为这是服务器端相对较新的技术,但不是主流之外的技术。@Michael sqlbot:握手失败(几乎?)与服务器证书的验证无关,因此信任存储上的更改不会有帮助。@Michael sqlbot是的,我看到了。我得出了与Steffen相同的结论,因此我还没有修补truststore,但如果我仍然卡住,可能需要测试:)@SteffenUllrich谢谢,我试图解决/驳回“如果可能的话,希望避免安装所有SSL证书”,但没有很好地传达我的想法。我想用这句话来表明,明确信任(“安装”)服务器的证书不应该是解决方案的一部分,除非信任存储是(不太可能的)根本原因,我看到它并没有真正以这种方式出现。我为不清楚道歉。你看到了吗?握手失败有许多不同的原因,但使用最新的信任存储,您似乎应该能够在不安装特定证书的情况下实现这一点。它似乎是CloudFlare的ECC证书,所以我认为这是服务器端相对较新的技术,但不是主流之外的技术。@Michael sqlbot:握手失败(几乎?)与服务器证书的验证无关,因此信任存储上的更改不会有帮助。@Michael sqlbot是的,我看到了。我得出了与Steffen相同的结论,因此我还没有修补truststore,但如果我仍然卡住,可能需要测试:)@SteffenUllrich谢谢,我试图解决/驳回“如果可能的话,希望避免安装所有SSL证书”,但没有很好地传达我的想法。我想用这句话来表明,明确信任(“安装”)服务器的证书不应该是解决方案的一部分,除非信任存储是(不太可能的)根本原因,我看到它并没有真正以这种方式出现。我为不够清晰而道歉。谢谢Steffen。你知道哪些额外的信息可能有用吗?Java版本是openJDK 1.7.0_85,这与我在本地环境中使用的版本相同,在本地环境中我不会得到任何错误。那么java版本可能是原因吗?主机名验证器应该是Apache的HTTPClient中始终返回true的验证器。@sébastienTromp:我建议查看所有其他与此相关的问题,即它们提供了哪些信息。也许已经有了一个完全适合你的环境的答案。但通常,启用TLS调试是一个不错的选择,或者是一个数据包捕获,这样人们就可以看到TLS握手的细节。我基本上看了所有我能找到的东西:)我将进一步研究TLS调试-目前看来Tomcat没有捕获输出