Java 线程 6,RECV TLSv1 警报:致命,握手失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30828759/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Thread-6, RECV TLSv1 ALERT: fatal, handshake_failure
提问by user955732
what is wrong with this code, it is supposed to trust all hosts, but it doesn't..
这段代码有什么问题,它应该信任所有主机,但它不......
It works fine with for example google.com but not with an API Gateway service running locally on my machine, why?
它适用于例如 google.com,但不适用于在我的机器上本地运行的 API 网关服务,为什么?
SSL DEBUG OUTPUT
SSL 调试输出
trigger seeding of SecureRandom done seeding SecureRandom Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 ... Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256 Allow unsafe renegotiation: false Allow legacy hello messages: true Is initial handshake: true Is secure renegotiation: false Thread-6, setSoTimeout(0) called %% No cached client session *** ClientHello, TLSv1 RandomCookie: GMT: 1434280256 bytes = { 216 ... 40 } Session ID: {} Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, .... SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV] Compression Methods: { 0 } Extension elliptic_curves, curve names: {secp256r1 .. secp256k1} Extension ec_point_formats, formats: [uncompressed]
Thread-6, WRITE: TLSv1 Handshake, length = 163 Thread-6, READ: TLSv1 Alert, length = 2 Thread-6, RECV TLSv1 ALERT: fatal, handshake_failure Thread-6, called closeSocket() Thread-6, handling exception: javax.net.ssl.SSLHandshakeException: **
Received fatal alert: handshake_failure
触发 SecureRandom 播种 SecureRandom 忽略不支持的密码套件:TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 ...忽略不支持的密码套件:TLS_RSA_WITH_AES_128_CBC_SHA256 允许不安全的重新协商:false 允许旧的 hello 消息:true 是初始安全的 set0 假手) 调用 %% 没有缓存的客户端会话 *** ClientHello, TLSv1 RandomCookie: GMT: 1434280256 bytes = { 216 ... 40 } Session ID: {} 密码套件: [TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, .... SSL_DHE_DSS_EDS_156_CBC_SHA, .... SSL_DHE_DSS_EDS_156_CBC_SHA, .... SSL_DHE_DSS_EDS_10000000000000000000000000000000000000000000, CSV_DHE_DSS_EDS_1434280256 bytes = { 216 ... 40 } Session ID:方法:{0} 扩展 elliptic_curves,曲线名称:{secp256r1 .. secp256k1} 扩展 ec_point_formats,格式:[未压缩]
Thread-6, WRITE: TLSv1 Handshake, length = 163 Thread-6, READ: TLSv1 Alert, length = 2 Thread-6, RECV TLSv1 ALERT: fatal, handshake_failure Thread-6, 调用 closeSocket() Thread-6, 处理异常: javax.net.ssl.SSLHandshakeException:**
收到致命警报:handshake_failure
**
**
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
public class ConnectHttps {
public static void main(String[] args) throws Exception {
/*
* fix for
* Exception in thread "main" javax.net.ssl.SSLHandshakeException:
* sun.security.validator.ValidatorException:
* PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
* unable to find valid certification path to requested target
*/
TrustManager[] trustAllCerts = [
[ getAcceptedIssuers: { -> null },
checkClientTrusted: { X509Certificate[] certs, String authType -> },
checkServerTrusted: { X509Certificate[] certs, String authType -> } ] as X509TrustManager
]
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
/*
* end of the fix
*/
//URL url = new URL("https://google.com"); //WORKS
URL url = new URL("https://localhost:8090"); // DOES NOT WORK, WHY?
URLConnection con = url.openConnection();
Reader reader = new InputStreamReader(con.getInputStream());
while (true) {
int ch = reader.read();
if (ch==-1) {
break;
}
System.out.print((char)ch);
}
}
}
Running the code found hereit shows that TLSv1.2 is not enabled on the client side:
运行此处找到的代码,它显示客户端未启用 TLSv1.2:
Supported Protocols: 5
SSLv2Hello
SSLv3
TLSv1
TLSv1.1
TLSv1.2Enabled Protocols: 2
SSLv3
TLSv1
支持的协议:5
SSLv2Hello
SSLv3
TLSv1
TLSv1.1
TLSv1.2启用的协议:2
SSLv3
TLSv1
回答by Steffen Ullrich
.. it is supposed to trust all hosts, but it doesn't..
.. RECV TLSv1 ALERT: fatal, handshake_failure Thread-6
..它应该信任所有主机,但它不......
.. RECV TLSv1 ALERT: 致命,handshake_failure Thread-6
A handshake failure alert from the server is unrelated to the validation of the servers certificate on the client and can thus not stopped by disabling certificate validation. Lots of things can cause such a failure, like no common ciphers, unsupported protocol version, missing SNI extension (only supported starting with JDK7). Since the error is issued by the server you might find more details about the problem in the servers log messages.
来自服务器的握手失败警报与客户端上服务器证书的验证无关,因此无法通过禁用证书验证来停止。很多事情都可能导致这样的失败,比如没有通用密码、不支持的协议版本、缺少 SNI 扩展(仅从 JDK7 开始支持)。由于错误是由服务器发出的,您可能会在服务器日志消息中找到有关该问题的更多详细信息。
EDIT: from the server logs the cause of the problem is visible:
编辑:从服务器日志可以看出问题的原因:
error handling connection: SSL protocol error error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher
错误处理连接:SSL 协议错误错误:1408A0C1:SSL 例程:SSL3_GET_CLIENT_HELLO:无共享密码
This means that there is no common cipher between client and server.
这意味着客户端和服务器之间没有通用密码。
A typical cause for this is a wrong setup of the certificates at the server. If you don't configure any certificates the server might require anonymous authentication with ADH ciphers, which are usually not enabled on the client side. I suggest that you check if you could connect with a browser.
造成这种情况的典型原因是服务器上的证书设置错误。如果您不配置任何证书,服务器可能需要使用 ADH 密码进行匿名身份验证,这通常不会在客户端启用。我建议您检查是否可以连接浏览器。
Another common misconfiguration is disabling all SSLv3 ciphers at the server in the believe that this is necessary to disable the SSL3.0 protocol (it is not). This effectively disables all ciphers except some new ciphers introduced with TLS 1.2. Modern browsers will be still able to connect but older clients not. This misconfiguration can be seen in this case (from the comment):
另一个常见的错误配置是禁用服务器上的所有 SSLv3 密码,因为认为这是禁用 SSL3.0 协议所必需的(事实并非如此)。这有效地禁用了除 TLS 1.2 引入的一些新密码之外的所有密码。现代浏览器仍然可以连接,但旧客户端不能。在这种情况下可以看到这种错误配置(从评论中):
From server log,, interface ciphers: FIPS:!SSLv3:!aNULL,,
从服务器日志,, 接口密码: FIPS:!SSLv3:!aNULL,,
!SSLv3
disables all ciphers available for version SSL3.0 and higher. This in effect leaves only the TLS1.2 ciphers because there are no new ciphers with TLS1.0 and TLS1.1. Since the client seems to be only support TLS1.0 there will be no shared ciphers:
!SSLv3
禁用可用于 SSL3.0及更高版本的所有密码。这实际上只剩下 TLS1.2 密码,因为 TLS1.0 和 TLS1.1 没有新密码。由于客户端似乎只支持 TLS1.0,因此不会有共享密码:
...WRITE: TLSv1 Handshake
...写入:TLSv1 握手
Use of !SSLv3
in the ciphers is usually caused by a lack of understanding of the difference between protocol version and ciphers. To disable SSLv3 you should only set the protocol accordingly but not the ciphers.
!SSLv3
在密码中使用 的使用通常是由于对协议版本和密码之间的差异缺乏了解造成的。要禁用 SSLv3,您应该只相应地设置协议,而不是密码。