You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot内嵌Jetty服务器TLSv1握手失败:无通用密码套件

Spring Boot内嵌Jetty服务器TLSv1握手失败解决方案

问题场景

运行在内嵌Jetty服务器上的Spring Boot REST API,被仅支持TLSv1的Java客户端调用时,出现以下错误:
fatal: engine already closed. Rethrowing javax.net.ssl.SSLHandshakeException: no cipher suites in common on spring boot embedded jetty server

客户端侧网络调试日志:

pool-2-thread-1, READ: TLSv1 Alert, length = 2  
pool-2-thread-1, RECV TLSv1.2 ALERT:  fatal, handshake_failure  
pool-2-thread-1, called closeSocket()  
pool-2-thread-1, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure  

尝试在application.properties中配置启用TLSv1,但未生效:

server.ssl.enabled=true
server.ssl.enabled-protocols=TLSv1
server.ssl.disabled-protocols=TLSv1.2
server.ssl.protocol=TLS
server.ssl.disabled-cipher-suites=

server.ssl.key-store-type=JKS  
server.ssl.keystore=keystore_path  
server.ssl.key-store-password=password  
server.ssl.key-alias=alias_name   
trust.store=truststore_path  
trust.store.password=password

服务器侧网络调试日志:

Using SSLEngineImpl.  
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_GCM_SHA384  
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA  
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384  
Allow unsafe renegotiation: false  
Allow legacy hello messages: true  
Is initial handshake: true  
Is secure renegotiation: false  
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 for TLSv1  
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_GCM_SHA256  
[Raw read]: length = 5  
0000: 16 03 01 00 63                                     ....c
[Raw read]: length = 99  
0000: 01 00 00 5F 03 01 63 AE   A7 33 45 C3 64 64 C9 BD  ..._..c..3E.dd..  
0010: BD 19 74 DA 21 29 8C 62   6B FB 32 67 86 C6 9A E0  ..t.!).bk.2g....  
0020: 91 04 3C 85 84 83 00 00   1E 00 FF C0 0A C0 14 00  ..<.............  
0030: 35 C0 05 C0 0F 00 39 00   38 C0 09 C0 13 00 2F C0  5.....9.8...../.  
0040: 04 C0 0E 00 33 00 32 01   00 00 18 00 0A 00 0A 00  ....3.2.........  
0050: 08 00 17 00 18 00 19 00   16 00 0B 00 02 01 00 00  ................  
0060: 17 00 00                                           ...  
qtp1209702763-21, READ: TLSv1 Handshake, length = 99  
*** ClientHello, TLSv1  
RandomCookie:  GMT: 1655547699 bytes = { 69, 195, 100, 100, 201, 189, 189, 25, 116, 218, 33,    41, 140, 98, 107, 251, 50, 103, 134, 198, 154, 224, 145, 4, 60, 133, 132, 131 }  
Session ID:  {}  
Cipher Suites: [TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,   TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA]  
Compression Methods:  { 0 }  
Extension elliptic_curves, curve names: {secp256r1, secp384r1, secp521r1, secp256k1}  
Extension ec_point_formats, formats: [uncompressed]  
Unsupported extension type_23, data:  
***  
[read] MD5 and SHA1 hashes:  len = 99  
0000: 01 00 00 5F 03 01 63 AE   A7 33 45 C3 64 64 C9 BD  ..._..c..3E.dd..  
0010: BD 19 74 DA 21 29 8C 62   6B FB 32 67 86 C6 9A E0  ..t.!).bk.2g....
0020: 91 04 3C 85 84 83 00 00   1E 00 FF C0 0A C0 14 00  ..<.............
0030: 35 C0 05 C0 0F 00 39 00   38 C0 09 C0 13 00 2F C0  5.....9.8...../.
0040: 04 C0 0E 00 33 00 32 01   00 00 18 00 0A 00 0A 00  ....3.2.........
0050: 08 00 17 00 18 00 19 00   16 00 0B 00 02 01 00 00  ................  
0060: 17 00 00                                           ...  
%% Initialized:  [Session-3, SSL_NULL_WITH_NULL_NULL]  
qtp1209702763-21, fatal error: 40: no cipher suites in common  
javax.net.ssl.SSLHandshakeException: no cipher suites in common  
%% Invalidated:  [Session-3, SSL_NULL_WITH_NULL_NULL]  
qtp1209702763-21, SEND TLSv1 ALERT:  fatal, description = handshake_failure  
qtp1209702763-21, WRITE: TLSv1 Alert, length = 2  
qtp1209702763-21, fatal: engine already closed.  Rethrowing  
 javax.net.ssl.SSLHandshakeException: no cipher suites in common  
qtp1209702763-21, called closeOutbound()  
qtp1209702763-21, closeOutboundInternal()  

问题分析

从服务器日志可以看出:

  1. 客户端发送的ClientHello明确使用TLSv1,且支持的密码套件包含TLS_RSA_WITH_AES_256_CBC_SHA、TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA等。
  2. 服务器日志中标记这些客户端支持的密码套件为Ignoring unavailable cipher suite,说明服务器未启用这些套件,导致双方没有共同的密码套件,握手失败。
  3. 仅配置启用TLSv1协议不足以解决问题,还需要确保服务器启用客户端支持的密码套件。

解决方案

1. 修改Spring Boot配置文件,指定支持的密码套件

更新application.properties,添加客户端支持的密码套件列表,覆盖默认配置:

server.ssl.enabled=true
server.ssl.enabled-protocols=TLSv1
server.ssl.disabled-protocols=TLSv1.2
server.ssl.protocol=TLS
# 指定客户端支持的密码套件
server.ssl.cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_DSS_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA

server.ssl.key-store-type=JKS  
server.ssl.keystore=keystore_path  
server.ssl.key-store-password=password  
server.ssl.key-alias=alias_name   
trust.store=truststore_path  
trust.store.password=password

2. 调整JVM参数(针对高版本JDK)

如果使用Java 8u161及以上版本,JDK默认禁用了部分旧版TLSv1密码套件,需要通过JVM参数启用:

-Djdk.tls.disabledAlgorithms="SSLv3, RC4, MD5withRSA, DH keySize < 1024, EC keySize < 224"

注意:不要清空所有禁用项,仅移除与TLSv1和目标密码套件相关的禁用规则,比如如果默认禁用了AES_256_CBC_SHA,需要从列表中删除。

3. 编程方式自定义Jetty SSL配置(如果配置文件不生效)

创建配置类,手动配置Jetty的SslContextFactory,确保启用TLSv1和对应密码套件:

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JettySslConfig {

    @Bean
    public WebServerFactoryCustomizer<JettyServletWebServerFactory> jettySslCustomizer() {
        return factory -> {
            factory.addServerCustomizers(server -> {
                SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
                // 配置证书信息
                sslContextFactory.setKeyStorePath("keystore_path");
                sslContextFactory.setKeyStorePassword("password");
                sslContextFactory.setKeyAlias("alias_name");
                sslContextFactory.setKeyStoreType("JKS");
                // 启用TLSv1
                sslContextFactory.setIncludeProtocols("TLSv1");
                // 指定支持的密码套件
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 23:40:29