簡體   English   中英

Java Spring Webflux:javax.net.ssl.SSLHandshakeException:空客戶端證書鏈

[英]Java Spring Webflux: javax.net.ssl.SSLHandshakeException: Empty client certificate chain

請詢問有關 Spring Webflux 應用程序的小問題。

定期但偶爾,在應用程序日志中,我會看到此堆棧跟蹤:

2022-02-04 09:20:13.813  WARN [myapplication,,] 11 --- [or-http-epoll-2] .s.ApplicationProtocolNegotiationHandler : [id: 0xc70400fa, L:/.<someIP>:<somePort> ! R:/<someOtherIP>:<someOtherPort>] TLS handshake failed:
javax.net.ssl.SSLHandshakeException: Empty client certificate chain
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) ~[na:na]
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117) ~[na:na]
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:336) ~[na:na]
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292) ~[na:na]
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:283) ~[na:na]
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1194) ~[na:na]
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1181) ~[na:na]
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) ~[na:na]
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443) ~[na:na]
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074) ~[na:na]
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061) ~[na:na]
    at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008) ~[na:na]
    at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1550) ~[netty-handler-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1396) ~[netty-handler-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1237) ~[netty-handler-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1286) ~[netty-handler-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:507) ~[netty-codec-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:446) ~[netty-codec-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) ~[netty-codec-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:795) ~[netty-transport-native-epoll-4.1.66.Final-linux-x86_64.jar!/:4.1.66.Final]
    at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480) ~[netty-transport-native-epoll-4.1.66.Final-linux-x86_64.jar!/:4.1.66.Final]
    at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378) ~[netty-transport-native-epoll-4.1.66.Final-linux-x86_64.jar!/:4.1.66.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) ~[netty-common-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.66.Final.jar!/:4.1.66.Final]
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.66.Final.jar!/:4.1.66.Final]
    at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]

不幸的是,當它出現時沒有模式。 在高流量、低流量、甚至沒有流量時,都會出現此消息。 而且這種情況只是偶爾出現,並非總是如此。

http 客戶端(Spring Webclient)構建如下:

    @Bean
    @Primary
    public WebClient getWebClient() {
        return WebClient.create().mutate().defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).clientConnector(new ReactorClientHttpConnector(HttpClient.create().wiretap(true).secure(sslContextSpec -> sslContextSpec.sslContext(getSslContext())))).build();
    }

public SslContext getSslContext() {
        try {
            final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            try (InputStream file = new FileInputStream(keyStorePath)) {
                final KeyStore keyStore = KeyStore.getInstance(keyStoreType);
                keyStore.load(file, keyStorePassPhrase.toCharArray());
                keyManagerFactory.init(keyStore, keyPassPhrase.toCharArray());
            }

            final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            try (InputStream trustStoreFile = new FileInputStream(trustStorePath)) {
                final KeyStore trustStore = KeyStore.getInstance(trustStoreType);
                trustStore.load(trustStoreFile, trustStorePassPhrase.toCharArray());
                trustManagerFactory.init(trustStore);
            }

            return SslContextBuilder.forClient().keyManager(keyManagerFactory).trustManager(trustManagerFactory).build();
        } catch (CertificateException | NoSuchAlgorithmException | IOException | KeyStoreException | UnrecoverableKeyException e) {
 LOGGER.error( "Error here: Empty client certificate chain?" + e, e);
            return null;
        }
    }

我很難理解根本原因以及此堆棧跟蹤的含義。

問題:

我看到這個 [id: 0xc70400fa, L:/.someIP:somePort R:/someOtherIP:someOtherPort ] 請問這個是什么意思? 從 Spring 文檔中,L 表示“本地”,R 表示“遠程”和。 意味着錯誤,因此,這是否意味着本地的 IP 正在嘗試與遠程的 IP“交談”? 但是當地人(我?)出示了一張空證書?

還是對面的遙控器正試圖與本地的我交談並出示空證書?

請求 ID(此處 ID:0xc70400fa)無法使用,因為無法與其他任何內容關聯。 請問如何正確使用這個ID?

最后,有沒有辦法了解為什么以及特別是什么時候(是 API 電話?健康檢查電話等)這個空客戶端證書鏈正在發生,請問如何防止它發生?

謝謝

您可以在 Spring 引導代碼中檢查一些配置參數,以查看其 SSL 實現的此類內容:

security.require-ssl=true
server.ssl.key-store:/home/user/folder/keystore.p12
server.ssl.key-store-password: XXXXXX              <========== your password
server.ssl.keyStoreType: PKCS12                    <========== your keystore format
server.ssl.keyAlias: XXXXX                         <========== your keystore alias

因此,您可以查看他們的源代碼以直接尋找他們的接口和提供的集成/實現。

因此,如果我們不需要,則不需要在我們的全局密鑰庫存儲庫中導入密鑰庫。 我們可以用另一種方式使用它。

[id: 0xc70400fa, L:/.someIP:somePort: R:/someOtherIP:someOtherPort]

  • id: 0xc70400fa => connection id (編輯感謝@Violeta)
  • L:/ip:port: R:/ip:port => localMachine:localPort 沒有連接到 remoteMachine:remotePort

或者,也許您可以嘗試另一種方式到 go:使用 wget、curl 或 Guzzle 或任何好的 HTTP(s) java 客戶端...也許還有企業服務總線 | 像 Apache Camel 這樣的中間件應用程序可以通過即插即用的方式連接任何未來的網絡服務或微服務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM