为何conn.getResponseCode()抛出SSLHandShakeException:handshake_failure
问题原因及解决方案
出现SSLHandShakeException: Received fatal alert: handshake_failure的核心原因是Java客户端与Moodle服务器的SSL/TLS握手协商失败,常见触发场景及解决方法如下:
1. Java加密套件与服务器不匹配
浏览器和curl默认支持的加密套件范围比老版本Java更广,若服务器要求的加密套件不在Java的启用列表中,就会触发握手失败。
- 排查方法:
用curl查看服务器支持的加密套件:
打印Java当前环境支持的加密套件:curl -v --tlsv1.2 https://proves.aprenonline.orgimport javax.net.ssl.SSLServerSocketFactory; public class CipherSuites { public static void main(String[] args) { SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); for (String suite : ssf.getSupportedCipherSuites()) { System.out.println(suite); } } } - 解决方法:
升级Java版本至Java 8u161+或Java 11及以上,新版本默认包含更完整的加密套件;若无法升级,可手动修改java.security文件,调整jdk.tls.enabledAlgorithms参数添加服务器需要的套件。
2. Java信任库未包含服务器根证书
浏览器和curl会自动信任主流CA签发的证书,但Java的默认信任库(cacerts)可能缺失目标服务器的根证书。
- 解决方法:
- 导出服务器证书:
openssl s_client -connect proves.aprenonline.org:443 < /dev/null | openssl x509 -outform PEM > moodle_server.crt - 将证书导入Java信任库(默认密码为
changeit):keytool -import -trustcacerts -alias moodle_proves -file moodle_server.crt -keystore $JAVA_HOME/jre/lib/security/cacerts
- 导出服务器证书:
3. TLS协议设置不生效
仅通过System.setProperty("https.protocols", "TLSv1.2")设置协议可能在部分环境中不生效,需手动指定SSLContext:
- 修改代码:
在创建HttpsURLConnection前添加如下代码:SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
4. 请求头缺失关键字段
浏览器和curl会自动发送User-Agent等请求头,部分服务器会拒绝无该字段的请求(虽不直接导致握手失败,但可能间接影响),可在代码中添加:
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36");
内容的提问来源于stack exchange,提问作者carles
相关产品推荐
相关产品推荐

