Java-HTTPS GET调用从EC2实例失败,握手失败,在本地工作
我的想法快用完了,这就是为什么我在这里寻求帮助。我有一个通过HTTPS进行REST调用的小类。我正在做一些清理工作,如果可能的话,我希望避免安装所有SSL证书 代码在本地运行得很好(来自Eclipse和独立的Tomcat),但每次从AWS 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.
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版本的问题,或者如果没有安装无限强度的加密扩展。握手失败可能是由许多不同的原因造成的,比如错误的Java版本、服务器设置、设置主机名验证器(无论如何都是个坏主意)、SNI。这个问题目前的信息不足以确定问题是什么 查看服务器的以下信息时,有两个信息看起来很有趣:
- 服务器需要SNI
- 服务器仅支持ECDHE密码
第二个问题可能是旧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没有捕获输出