【发布时间】:2021-06-21 10:13:17
【问题描述】:
我有下面的代码来配置密码列表并发送到Netty客户端中的服务器。
Pair<String, String> config = Pair.of(keyStore, keyStorePassword);
if (!filters.containsKey(config)) {
HttpClient securedClient = this.httpClient.secure(sslContextSpec -> {
SslContextBuilder sslContextBuilder = SslContextBuilder.forClient();
sslContextBuilder.keyManager(loadKeyStore(keyStore, keyStorePassword));
sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
if(!StringUtils.isBlank(ciphers)) {
sslContextBuilder.ciphers(getCiphersList(ciphers));
}
sslContextSpec.sslContext(sslContextBuilder);
});
filters.put(config, new NettyRoutingFilter(securedClient, headersFilters, properties));
}
return filters.get(config).filter(exchange, chain);
这段代码运行良好。最近spring boot和cloud版本升级,之后出现SSL握手失败。
根据服务器端 SSL 调试日志,此故障是由于 no ciphers suites in common 错误。
我进一步检查并发现客户端正在尝试与 TLSv1.2 启动握手,并且在我看来 Netty 已过滤掉配置的密码 (TLS_DHE_DSS_WITH_AES_256_GCM_SHA384)。
我可以在客户端的 SSL 日志中看到以下两个日志部分,只有第二部分到达服务器。 (没有TLS_DHE_DSS_WITH_AES_256_GCM_SHA384)
javax.net.ssl|DEBUG|34|es-writer-6|2021-03-25 10:48:25.081 SGT|ClientHello.java:651|Produced ClientHello handshake message (
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "47 5B 0F EB C7 9C 1B A1 21 C0 60 15 AC FD 5B 88 67 07 F9 2B 04 4A 74 ED 9B 37 CD 84 81 65 87 F8",
"session id" : "33 FD 38 2C 7D 71 62 79 2E F1 99 7D FB 5F 69 F6 04 23 9A 31 04 9B 5D 0A 16 B2 76 10 A3 C5 74 E6",
"cipher suites" : "[TLS_AES_128_GCM_SHA256(0x1301), TLS_AES_256_GCM_SHA384(0x1302), TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(0xC02E), TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(0xC032), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(0xC02D), TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(0xC031), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(0xC024), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(0xC028), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(0xC026), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(0xC02A), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(0xC00A), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(0xC005), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(0xC00F), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(0xC023), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(0xC027), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(0xC025), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(0xC029), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(0xC009), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(0xC004), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(0xC00E), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032), TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]",
javax.net.ssl|DEBUG|2D|reactor-http-nio-1|2021-03-25 10:48:25.275 SGT|ClientHello.java:651|Produced ClientHello handshake message (
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "48 3A 89 68 7F CE 49 83 FE EF 12 81 2D E3 EE 54 47 90 A8 33 EE 95 F6 16 76 B9 81 41 E9 DA B6 2E",
"session id" : "69 CC E2 A3 BA 6A AF 47 8B 3E 83 53 4E 5F 62 90 B3 91 F3 E3 9D 5C 1A 2D C3 F7 F7 6D 2E EA 38 7C",
"cipher suites" : "[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_AES_128_GCM_SHA256(0x1301), TLS_AES_256_GCM_SHA384(0x1302)]",
即使它们已过时(弱),如何发送配置的密码? SslContextBuilder 这里的配置有什么问题吗?
更新:
进一步分析有助于找出错过配置密码的真正原因。
作为 Spring boot 版本升级的一部分,reactorNetty 版本已从 0.9.12 升级到 1.0.3。
我可以看到以下 reactor.netty.tcp.SslProvider
的逻辑差异0.9.12
void updateDefaultConfiguration() {
switch(this.type) {
case H2:
this.sslContextBuilder.sslProvider(io.netty.handler.ssl.SslProvider.isAlpnSupported(io.netty.handler.ssl.SslProvider.OPENSSL) ? io.netty.handler.ssl.SslProvider.OPENSSL : io.netty.handler.ssl.SslProvider.JDK).ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE).applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.ALPN, SelectorFailureBehavior.NO_ADVERTISE, SelectedListenerFailureBehavior.ACCEPT, new String[]{"h2", "http/1.1"}));
break;
case TCP:
this.sslContextBuilder.sslProvider(OpenSsl.isAvailable() ? io.netty.handler.ssl.SslProvider.OPENSSL : io.netty.handler.ssl.SslProvider.JDK);
case NONE:
}
}
1.0.3
void updateDefaultConfiguration() {
switch(this.type) {
case H2:
this.sslContextBuilder.sslProvider(io.netty.handler.ssl.SslProvider.isAlpnSupported(io.netty.handler.ssl.SslProvider.OPENSSL) ? io.netty.handler.ssl.SslProvider.OPENSSL : io.netty.handler.ssl.SslProvider.JDK).ciphers(HTTP2_CIPHERS, SupportedCipherSuiteFilter.INSTANCE).applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.ALPN, SelectorFailureBehavior.NO_ADVERTISE, SelectedListenerFailureBehavior.ACCEPT, new String[]{"h2", "http/1.1"}));
break;
case TCP:
this.sslContextBuilder.sslProvider(OpenSsl.isAvailable() ? io.netty.handler.ssl.SslProvider.OPENSSL : io.netty.handler.ssl.SslProvider.JDK).ciphers((Iterable)null, IdentityCipherSuiteFilter.INSTANCE).applicationProtocolConfig((ApplicationProtocolConfig)null);
case NONE:
}
}
在 1.0.3 中,它强制将密码覆盖为 null,并且不再能够手动设置密码。
我该如何解决这个问题?
【问题讨论】:
标签: java netty spring-cloud sslhandshakeexception reactor-netty