问题
所以,我有一台我需要连接的服务器,它使用旧的,已弃用的证书。如果我尝试使用Apache HttpClient
与其建立联系,我会获得SSLException: Received fatal alert: close_notify
。客户端本身不需要可重用于其他服务器,但构建器代码必须能够。
我不太理想的解决方法
我通过设置回退TLS协议解决了这个问题,但它并不理想,因为它增加了另一个请求。必须有一个比这更优雅的方式:
URL url = new URL("https://...");
SSLContextBuilder sslContextBuilder = SSLContexts.custom();
try {
url.openConnection().connect();
} catch (SSLException e) {
sslContextBuilder.useProtocol("TLSv1");
}
我也尝试了
我还尝试创建自定义SSLConnectionSocketFactory
,但如果TLSv1
作为选项包含,则apache会忽略TLSv1.2
。
SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(
SSLContext.getDefault(),
new String[] { "TLSv1.2", "TLSv1" },
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
反射
实质上,我认为基本问题是远程服务器使用不推荐使用的密码套件。我可以将我想要支持的所有密码套件传递到SSLConnectionSocketFactory
,但是有很多,Sun已经隐藏了私有类背后的完整列表。
答案 0 :(得分:1)
您可以通过删除$ JAVA_HOME / jre / lib / security / java.security中的jdk.tls.disabledAlgorithms
来使用不推荐使用的密码套件(例如SSL_RSA_WITH_RC4_128_SHA)。
e.g。默认HttpClient访问的https://ex.qq.com/将返回Received fatal alert: handshake_failure
。但是下面的代码可以工作:
public static void main(String[] args) throws Exception {
HttpClientBuilder builder = HttpClientBuilder.create().
setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContext.getDefault(),
new String[] {"TLSv1"}, new String[] {"SSL_RSA_WITH_RC4_128_SHA"}, new DefaultHostnameVerifier()));
try (CloseableHttpClient client = builder.build()) {
HttpGet get = new HttpGet("https://ex.qq.com/");
System.out.println(client.execute(get).getStatusLine().getStatusCode());
}
}
有关详细信息,请参阅此问题:Received fatal alert: handshake_failure through SSLHandshakeException