这段代码有什么问题,它应该信任所有主机,但事实并非如此。
例如,它可以在 google.com 上正常运行,但不能在我的计算机上本地运行的 API 网关服务上运行,为什么?
SSL 调试输出
触发 SecureRandom 的播种 完成播种 SecureRandom 忽略
不支持的密码套件:TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 ...
忽略不支持的密码套件:TLS_RSA_WITH_AES_128_CBC_SHA256
允许不安全的重新协商: false 允许旧版 hello 消息: true 是
初始握手: true 是否安全重新协商: false Thread-6,
setSoTimeout(0) 调用 %% 没有缓存的客户端会话
*** ClientHello,TLSv1 RandomCookie:GMT:1434280256 字节 = { 216 ... 40 } 会话 ID:{} 密码套件:
[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] 压缩方法:{ 0 }
扩展 elliptic_curves,曲线名称:{secp256r1 .. secp256k1}
扩展 ec_point_formats,格式:[未压缩]
线程 6,写入:TLSv1 握手,长度 = 163 线程 6,读取:TLSv1
警报,长度 = 2 线程 6,RECV TLSv1 警报:致命,
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 代码在这里找到 https://bugs.launchpad.net/ubuntu/+source/openjdk-7/+bug/1314113它表明客户端未启用 TLSv1.2:
支持的协议:5
SSLv2Hello
SSLv3
TLSv1
TLSv1.1
TLSv1.2
启用的协议:2
SSLv3
TLSv1
..它应该信任所有主机,但事实并非如此..
.. RECV TLSv1 警报:致命,握手失败线程 6
来自服务器的握手失败警报与客户端上服务器证书的验证无关,因此不能通过禁用证书验证来停止。很多事情都会导致这样的失败,比如没有通用的密码、不支持的协议版本、缺少 SNI 扩展(仅从 JDK7 开始支持)。由于错误是由服务器发出的,您可能会在服务器日志消息中找到有关该问题的更多详细信息。
编辑:从服务器日志中可以看出问题的原因:
错误处理连接:SSL 协议错误错误:1408A0C1:SSL 例程:SSL3_GET_CLIENT_HELLO:无共享密码
这意味着客户端和服务器之间没有通用密码。
造成这种情况的典型原因是服务器上的证书设置错误。如果您不配置任何证书,服务器可能需要使用 ADH 密码进行匿名身份验证,这通常在客户端未启用。建议您检查一下浏览器是否可以连接。
另一种常见的错误配置是禁用服务器上的所有 SSLv3 密码,因为我们认为这是禁用 SSL3.0 协议所必需的(但事实并非如此)。这实际上会禁用除 TLS 1.2 引入的一些新密码之外的所有密码。现代浏览器仍然能够连接,但旧客户端则无法连接。在这种情况下可以看到这种错误配置(来自评论):
从服务器日志,接口密码:FIPS:!SSLv3:!aNULL,
!SSLv3
禁用 SSL3.0 版本可用的所有密码及更高。这实际上只留下了 TLS1.2 密码,因为没有新的 TLS1.0 和 TLS1.1 密码。由于客户端似乎只支持 TLS1.0,因此不会有共享密码:
...写入:TLSv1 握手
Use of !SSLv3
密码中的问题通常是由于缺乏对协议版本和密码之间差异的理解而引起的。要禁用 SSLv3,您应该只相应地设置协议,而不是密码。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)