【问题标题】:Cipher list configured in Netty client not being sent down to ServerNetty 客户端中配置的密码列表未发送到服务器
【发布时间】: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


    【解决方案1】:

    最后,我发现 SSL 上下文需要在分配给新反应器 Netty 版本中的上下文规范之前构建。

    工作代码:

    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));
     }
     try {
        sslContextSpec.sslContext(sslContextBuilder.build());
     } catch (SSLException e) {
       log.error("Error in building the SSL context ",e);
     }
    });
    

    【讨论】:

      猜你喜欢
      • 2017-03-08
      • 2015-02-10
      • 1970-01-01
      • 2014-04-15
      • 1970-01-01
      • 2012-12-05
      • 1970-01-01
      • 2015-05-02
      • 1970-01-01
      相关资源
      最近更新 更多