在一次使用 Netty 做服务端进行 TLS 通信开发的过程中,客户端与服务端握手总是失败。经过多番排查,最终发现问题出在了 TLS 协议版本的不兼容 —— Java 从某个版本开始默认禁用了 TLS 1.0 和 1.1。本文将围绕这个问题展开,帮助开发者理清 Java 中 TLS 协议版本的支持情况,以及如何合理配置以保证通信顺利进行。
📌 背景:一次 Netty SSL 握手失败
在实现服务端 SSLContext 初始化时,我们使用了如下代码:
typescript
代码解读
复制代码
private SSLEngine getSslServerEngine() { SSLEngine sslEngine = getServerContext().createSSLEngine(); sslEngine.setUseClientMode(SSLConfig.NEED_CLIENT_AUTH); sslEngine.setEnabledProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}); sslEngine.setNeedClientAuth(SSLConfig.NEED_CLIENT_AUTH); return sslEngine; }
可以看到,为了兼容旧客户端,我们手动开启了 "TLSv1", "TLSv1.1" 和 "TLSv1.2"。
然而在实际运行过程中,客户端始终握手失败。服务端日志打印握手失败,客户端报错为 handshake_failure,甚至 protocol_version。经过深入排查,最终发现——Java 的某些版本默认禁用了 TLSv1 和 TLSv1.1,导致 SSL 引擎虽然设置了这些协议,却根本无法启用。
✅ 关键版本:Java 1.8.0_291
从 Java 8u291(即 1.8.0_291)开始,Oracle 和 OpenJDK 默认在安全策略中 禁用了 TLS 1.0 和 1.1。
这是通过修改 java.security 文件中的如下配置实现的:
ini
代码解读
复制代码
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \ DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ include jdk.disabled.namedCurves
🔍 如何查看当前禁用状态?
先使用java -version查看小版本确定高于1.8.0_291,你可以在你的 JDK 安装目录中找到 lib/security/java.security 文件,查找 jdk.tls.disabledAlgorithms 这一项。
🔧 解决方案
✅ 推荐:只使用 TLSv1.2+
修改你的代码和服务端配置,只启用 TLS 1.2 或以上协议:
arduino
代码解读
复制代码
sslEngine.setEnabledProtocols(new String[]{"TLSv1.2"});
确保客户端也支持 TLSv1.2。
⚠️ 临时方案:修改默认安全配置(不推荐生产使用)
打开 java.security 文件,移除禁用项:
ini
代码解读
复制代码
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, ...
⚠️ 不建议直接修改 JDK 全局配置,容易影响其他系统组件。
💡 更安全的做法:使用自定义 java.security 配置文件
创建一个自定义配置文件,例如:
bash
代码解读
复制代码
./resources/conf/custom-java.security
内容为(只包含你要覆盖的项):
ini
代码解读
复制代码
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, ...
然后在启动 Java 应用时,指定该文件:
ini
代码解读
复制代码
-Djava.security.properties=./resources/conf/custom-java.security
✅ 这种方式不会影响全局 JDK 安装,是推荐的替代方案。
⚠️ 强烈建议仅在必要场景下使用此方法,并计划尽快升级使用 TLS 1.2 或 TLS 1.3。
💡 建议
- 优先使用 TLS 1.2 或 TLS 1.3,尤其是在生产环境。
- 检查你的服务端和客户端的协议支持情况,确保兼容。
- 使用工具如
nmap、openssl s_client等检查 TLS 支持情况。
🔚 总结
- Java 从 1.8.0_291 起默认禁用了 TLSv1 和 TLSv1.1
- 设置
SSLEngine.setEnabledProtocols(...)不能绕过此禁用 - 推荐升级所有客户端支持 TLSv1.2+
- 如果必须兼容旧协议,使用自定义
java.security文件 + 启动参数是最佳实践
这一改变对提高安全性至关重要。开发者需要了解这个变化对现有应用的影响,并尽快进行适配升级。
4731

被折叠的 条评论
为什么被折叠?



