对于javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure错误某一种情况的处理
一般出现 javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 错误看名字就是握手的时候发生问题(废话)可能原因也以下几点:
- 客户端和服务器支持的SSL/TLS版本不兼容。
- 客户端支持的加密套件列表与服务器不匹配。
- 服务器的SSL证书可能不可信或已过期。
- 客户端的安全套件配置错误或不正确。
首先在网络请求时候打开日志:
System.setProperty("javax.net.debug", "ssl:handshake");
然后对比到底是哪部分出现错误;
我这里遇见的是加密套件不匹配:(请看一段简单网络请求代码)
HttpClient httpClient = null;
try {
//System.setProperty("javax.net.debug", "all");
System.setProperty("javax.net.debug", "ssl:handshake"); //开启ssl日志
System.setProperty("jdk.internal.httpclient.disableHostnameVerification","true");//取消主机名验证
SSLParameters sslParameters = new SSLParameters();
//sslParameters.setProtocols(new String[]{ "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3", "SSLv2Hello" });
SSLContext sslContext = SSLContext.getInstance("TLS");
//忽略证书验证
sslContext.init(null, new TrustManager[]{ new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0];}
}}, null);
httpClient = HttpClient.newBuilder()
.sslParameters(sslParameters)
.sslContext(new SSLHelper().sslContext())
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
String str = "请求地址";
var request = HttpRequest.newBuilder().GET().uri(new URI(str))
.header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.46")
.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
.build();
HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder().GET().uri(new URI(str)).build(),
HttpResponse.BodyHandlers.ofString());
System.err.println(response);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(httpClient != null) httpClient.close();
}
出现的异常:(部分展示)
javax.net.ssl|DEBUG|02|HttpClient-1-Worker-0|2024-08-29 15:30:58.921 CST|ClientHello.java:640|Produced ClientHello handshake message (
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "2465D4171866802D69373DAE605B1835AA835105305A214D301D5D85D4253442",
"session id" : "E6AA3EECCE23680853EFAC383D83B7BFFCA8571A40BB82B1F3A5F22189117EED",
"cipher suites" : "[TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301), ...
...
}
...
...
javax.net.ssl|DEBUG|02|HttpClient-1-Worker-0|2024-08-29 15:30:59.000 CST|ServerHello.java:883|Consuming ServerHello handshake message (
"ServerHello": {
"server version" : "TLSv1.2",
"random" : "F79E21C1219933F82DD6353C907BAF05853450DA6C2AE01775177F595DACA139",
"session id" : "",
"cipher suite" : "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030)",
"compression methods" : "00",
...
}
...
...
javax.net.ssl|DEBUG|02|HttpClient-1-Worker-0|2024-08-29 15:30:59.023 CST|CertificateMessage.java:360|Consuming server Certificate handshake message (
"Certificates": [
"certificate" : {
"version" : "v3",
"serial number" : "201501527BDE42E4F886C2B545AFC937",
"signature algorithm": "SHA256withRSA",
"issuer" : "CN=***, O=***, C=CN",
"not before" : "2024-03-24 14:25:07.000 CST",
"not after" : "2025-01-27 16:31:11.000 CST",
"subject" : "CN=******",
"subject public key" : "RSA",
...
}
...
...
javax.net.ssl|DEBUG|02|HttpClient-1-Worker-0|2024-08-29 15:30:59.088 CST|Alert.java:232|Received alert message (
"Alert": {
"level" : "fatal",
"description": "handshake_failure"
}
...
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:956)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:133)
at network.LocalNetworkTest.main(LocalNetworkTest.java:50)
...
(不了解日志的同学可以先看看这位大佬写的:SSL/TLS 握手过程详解)
从异常信息里面看出,协议没问题,证书签名处挂了!密码套件没匹配上!
看出来对方使用的 SHA256withRSA 加密,我们客户端也要加上相印的加密套件才行
(把下面代码加在上面示例中相应位置即可)
sslParameters.setCipherSuites(new String[]{ "TLS_RSA_WITH_AES_256_CBC_SHA256" });
再次请求:OK!