Java调用ssl异常(javax.net.ssl.SSLHandshakeException: No appropriate protocol)

本文介绍了当遇到Java SSLHandshakeException,提示No appropriate protocol时的解决方法。问题通常与JDK的SSL配置有关。作者分析了TLS协议的使用,并指出禁用某些协议可能导致网络通信失败。解决方案是检查并修改`java.security`文件中禁用的TLS协议,释放被禁用的协议以允许正确的SSL连接。通过这种方式,作者成功解决了数据库连接超时的问题。

这个问题的出现, 基本上跟你项目启动的jdk有关系, 不是绝对的.
今天我本地启动调用远程数据库的时候出现了这个问题, 数据库链接不上. 一直连接超时
最后导致的问题就是Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

搜网上大部分的内容, 都是要求删除jdk/security包下面java.security文件中SSLv3
但是异常现象依然存在,
后来分析了一下jdk.tls.disabledAlgorithms禁用的一些协议算法

其中:
互联网的通信安全,建立在SSL/TLS协议之上, 
目前,应用最广泛的是TLS 1.0,接下来是SSL 3.0。但是,主流浏览器都已经实现了TLS 1.2的支持。TLS(传输层安全)是更为安全的升级版 SSL。

所以要根据你们请求的外部资源的处理方式做判断, 禁用某种协议可能就会造成网路不通. 请求超时失败. 

我这边的处理是, 把禁用对应的tls协议释放掉. 就可以链接成功了. 你们可以尝试一下.

jdk文件目录: jdk/jre/lib/security/java.security

<think> 我们遇到了一个SSLHandshakeException,错误信息是"No appropriate protocol (protocol is disabled or cipher suites are inappropriate)"。这个异常通常发生在客户端和服务器尝试建立SSL/TLS连接时,但双方无法协商出一个共同支持的协议版本或加密套件。 ### 问题原因 1. **协议不匹配**:客户端支持的协议版本(如TLSv1.2)在服务器端被禁用,或服务器端支持的协议版本客户端不支持。 2. **加密套件不匹配**:客户端和服务器没有共同支持的加密套件。 3. **Java安全策略限制**:使用的Java版本可能默认禁用了某些协议(如Java 8默认禁用SSLv3,Java 11默认禁用TLSv1和TLSv1.1等)。 ### 解决方案 #### 方案1:在代码中显式设置协议版本 如果是你作为客户端发起请求,你可以在创建SSL连接时指定协议版本。例如,使用`HttpsURLConnection`: ```java import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import java.net.URL; public class SSLExample { public static void main(String[] args) throws Exception { // 指定使用TLSv1.2协议 SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, null); // 使用默认的密钥管理器和信任管理器 // 设置全局的SSL上下文 HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); URL url = new URL("https://example.com"); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); // ... 使用连接 } } ``` #### 方案2:修改JVM参数 在启动JVM时,通过参数指定启用的协议版本。例如,启用TLSv1.2和TLSv1.3: ```bash java -Djdk.tls.client.protocols=TLSv1.2,TLSv1.3 ... YourApp ``` #### 方案3:检查并修改服务器配置 如果是你的服务器(如Tomcat)出现此问题,请确保服务器配置了正确的协议和加密套件。例如,在Tomcat的`server.xml`中配置: ```xml <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true"> <SSLHostConfig> <Protocols useServerCipherSuitesOrder="true" sslProtocol="TLS" sslEnabledProtocols="TLSv1.2,TLSv1.3"/> <!-- 配置加密套件(可选) --> <Ciphers ciphers="TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,..."/> </SSLHostConfig> <!-- 其他配置 --> </Connector> ``` #### 方案4:检查Java安全策略 查看`java.security`文件(位于`$JAVA_HOME/conf/security/java.security`)中关于`jdk.tls.disabledAlgorithms`的配置。确保你没有禁用需要的协议。 例如,如果希望启用TLSv1.2,则确保该协议不在禁用列表中: ``` # 修改前可能包含: jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, ... # 修改后(移除TLSv1.2): jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, ... # 注意:如果TLSv1.2没有被列出,则它是启用的。 ``` ### 调试技巧 1. 使用`-Djavax.net.debug=ssl:handshake`参数运行程序,可以打印详细的SSL握手日志,帮助诊断问题。 2. 使用在线工具(如SSL Labs的SSL Server Test)测试服务器配置。 ### 注意事项 - 在Java 8中,默认启用的协议是TLSv1.0、TLSv1.1和TLSv1.2(具体取决于更新版本)。在Java 11中,TLSv1.0和TLSv1.1默认被禁用。 - 确保客户端和服务器至少有一个共同的协议和加密套件。 ### 总结 该异常通常是由于协议或加密套件不匹配引起的。我们可以通过显式设置协议版本、调整JVM参数、修改服务器配置或调整Java安全策略来解决。 --- ### §§相关问题§§: 1. 如何查看Java默认支持的SSL/TLS协议版本? 2.Java中如何自定义SSLContext以使用特定的协议和加密套件? 3. 如何解决Java 11中因TLSv1.1被禁用导致的握手失败? 4. 在Tomcat中配置SSL时,如何设置仅使用强密码套件? </think> ### SSLHandshakeException: No appropriate protocol 问题分析与解决方案 这个异常表示客户端和服务器在SSL/TLS握手过程中无法协商出共同支持的协议版本或加密套件。以下是根本原因和解决方案: #### 📌 问题原因 1. **协议版本不匹配**: - 客户端尝试使用服务器已禁用的协议(如 TLSv1.0/TLSv1.1) - 服务器配置了更高版本的协议(如 TLSv1.3)但客户端不支持 2. **加密套件不兼容**: - 客户端支持的加密套件与服务器配置不匹配 3. **Java安全策略限制**: - `jdk.tls.disabledAlgorithms` 配置禁用了特定协议 4. **中间设备干扰**: - 防火墙或代理设备过滤了特定协议 #### 🔧 解决方案(Java客户端侧) ##### 方案1:强制指定协议版本(推荐) ```java public class SSLProtocolFixer { public static void main(String[] args) throws Exception { // 创建自定义SSL上下文 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, null, null); // 设置启用的协议列表(确保包含服务器支持的协议) SSLParameters params = new SSLParameters(); params.setProtocols(new String[]{"TLSv1.2", "TLSv1.3"}); // 添加所需协议 // 创建自定义连接器 try (CloseableHttpClient httpClient = HttpClients.custom() .setSSLContext(sslContext) .setSSLParameters(params) .build()) { HttpGet request = new HttpGet("https://your-api-endpoint.com"); try (CloseableHttpResponse response = httpClient.execute(request)) { // 处理响应 } } } } ``` ##### 方案2:修改JVM全局设置(启动参数) ```bash java -Djdk.tls.client.protocols=TLSv1.2,TLSv1.3 -jar your-app.jar ``` #### 解决方案(服务器侧 - Tomcat配置) 在 `conf/server.xml` 中配置: ```xml <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" sslEnabledProtocols="TLSv1.2,TLSv1.3" ciphers="TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, ..."> <!-- 其他SSL配置 --> </Connector> ``` #### 🔍 诊断工具:检查支持的协议 ```java public class ProtocolChecker { public static void main(String[] args) { Arrays.stream(SSLContext.getDefault().getSupportedSSLParameters().getProtocols()) .forEach(System.out::println); } } ``` #### ⚠ 重要注意事项 1. **安全警告**: - 不要启用不安全的旧协议(SSLv3, TLSv1.0, TLSv1.1) - 推荐最小使用TLSv1.2,优先使用TLSv1.3 2. **Java版本影响**: - Java 8u292+ 默认禁用TLSv1.0/v1.1 - Java 11+ 默认仅启用TLSv1.2/v1.3 3. **配置检查**: - 检查 `$JAVA_HOME/conf/security/java.security` 文件 - 查看 `jdk.tls.disabledAlgorithms` 设置 #### 测试建议 使用OpenSSL测试服务器支持: ```bash openssl s_client -connect your-server:443 -tls1_2 openssl s_client -connect your-server:443 -tls1_3 ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值