这段代码有什么问题,它应该信任所有主机,但它不会…
它适用于例如google.com,但没有在我的机器上本地运行的API网关服务,为什么?
SSL DEBUG OUTPUT
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
**
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);
}
}
}
运行the code found here,表明客户端未启用TLSv1.2:
Supported Protocols: 5
SSLv2Hello
SSLv3
TLSv1
TLSv1.1
TLSv1.2Enabled Protocols: 2
SSLv3
TLSv1
解决方法:
.. it is supposed to trust all hosts, but it doesn’t..
.. RECV TLSv1 ALERT: fatal, handshake_failure Thread-6
来自服务器的握手失败警报与客户端上的服务器证书的验证无关,因此无法通过禁用证书验证来停止.很多事情都可能导致这样的失败,例如没有通用密码,不支持的协议版本,缺少SNI扩展(仅支持从JDK7开始).由于服务器发出错误,您可能会在服务器日志消息中找到有关该问题的更多详细信息.
编辑:从服务器日志中可以看到问题的原因:
error handling connection: SSL protocol error error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher
这意味着客户端和服务器之间没有通用密码.
造成这种情况的典型原因是服务器上的证书设置错误.如果您未配置任何证书,则服务器可能需要使用ADH密码进行匿名身份验证,这些密码通常在客户端未启用.我建议您检查是否可以连接浏览器.
另一个常见的错误配置是禁用服务器上的所有SSLv3密码,相信这是禁用SSL3.0协议所必需的(事实并非如此).这有效地禁用了除TLS 1.2引入的一些新密码之外的所有密码.现代浏览器仍然可以连接,但不是老客户端.在这种情况下可以看到这种错误配置(来自评论):
From server log,, interface ciphers: FIPS:!SSLv3:!aNULL,,
!SSLv3禁用可用于SSL3.0及更高版本的所有密码.这实际上只留下了TLS1.2密码,因为没有TLS1.0和TLS1.1的新密码.由于客户端似乎只支持TLS1.0,因此不会有共享密码:
…WRITE: TLSv1 Handshake
在密码中使用!SSLv3通常是由于缺乏对协议版本和密码之间差异的理解.要禁用SSLv3,您应该只相应地设置协议,而不是密码.