证书链完整,okhttp3请求错误?

证书情况

myssl.com验证证书是正常的
https://myssl.com/ynslyszx.com

浏览器中查看

image.png

使用命令查看

image.png

测试代码

public static void main(String[] args) {

        String url = "https://ynslyszx.com/fp04/ldt-service/msp/getPublicKey.do";
        OkHttpClient client = new OkHttpClient();
        // 指定你要请求的URL
        Request request = new Request.Builder()
                .url(url)
                .build();
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            // 打印响应体的内容
            System.out.println(response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

错误信息

使用okhttp请求报错:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:353)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:296)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:291)
    at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:652)
    at sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:471)
    at sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:367)
    at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:376)
    at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
    at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:422)
    at sun.security.ssl.TransportContext.dispatch(TransportContext.java:183)
    at sun.security.ssl.SSLTransport.decode(SSLTransport.java:154)
    at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1279)
    at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1188)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:373)
    at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:379)
    at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
    at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
    at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
    at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
    at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
    at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
    at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
    at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
    at org.example.App.main(App.java:35)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
    at sun.security.validator.Validator.validate(Validator.java:271)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:312)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:221)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:128)
    at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:636)
    ... 29 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)
    ... 35 more

问题

  1. 同样的代码,请求https://baidu.comhttps://qq.com是正常的,请求ynslyszx.com就出错;使用myssl.com验证后,证书也是正常的,请问是哪个环节出错?
  2. 服务器中尝试用myssl.com修复过证书,也是请求不通。
  3. 目前解决办法是使okhttp3忽略全部证书验证,但是这样不太合适,请问是否有其他解决方案?
阅读 758
avatarAI BotBETA

问题解答

  1. 同样的代码,请求https://baidu.comhttps://qq.com是正常的,请求ynslyszx.com就出错;使用myssl.com验证后,证书也是正常的,请问是哪个环节出错?

    问题出在Java的默认信任库(truststore)中没有包含ynslyszx.com的证书链中的某个或多个中间证书。虽然myssl.com验证了证书是有效的,但它并不涉及Java运行时的信任库配置。Java运行时(如JDK)使用一个内置的或可配置的信任库来验证SSL/TLS连接的证书链。如果证书链中的某个中间证书不在信任库中,Java将无法构建完整的证书路径,从而导致PKIX path building failed错误。

  2. 服务器中尝试用myssl.com修复过证书,也是请求不通。

    修复证书可能只解决了服务器端的证书问题,但客户端(在这个例子中是Java环境)仍然需要能够验证服务器证书的完整性和有效性。如果Java的信任库中没有必要的中间证书,即使服务器证书是新的和有效的,客户端也会因为无法验证证书链而拒绝连接。

  3. 目前解决办法是使okhttp3忽略全部证书验证,但是这样不太合适,请问是否有其他解决方案?

    是的,忽略证书验证(例如,通过自定义TrustManager来接受所有证书)虽然可以解决问题,但会极大地降低安全性,因为它使你的应用程序容易受到中间人攻击(MITM)。更安全的解决方案包括:

    • 更新Java信任库:如果你控制Java运行环境,可以尝试将缺失的中间证书添加到Java的默认信任库中。这通常涉及下载中间证书,然后使用keytool工具将其导入到cacerts文件中。
    • 使用自定义TrustManager:如果你不想修改全局信任库,可以只在你的应用程序中使用一个自定义的TrustManager,该TrustManager仅信任特定的证书或证书链。这比完全忽略证书验证更安全,但你需要确保只信任可靠的证书。
    • 与服务器管理员合作:联系ynslyszx.com的服务器管理员,要求他们提供完整的证书链,并确保所有必要的中间证书都正确配置在服务器上。这样,客户端(包括Java环境)就能更容易地验证服务器证书。
    • 使用系统属性或JVM参数:在某些情况下,你可以通过系统属性或JVM参数来指定一个不同的信任库文件,该文件包含了你需要的所有证书。

    推荐的做法是尽可能更新和配置信任库,以包含所有必要的证书,从而保持应用程序的安全性。

1 个回答

java的信任ca是自己私有的。不跟操作系统的混一起。cfca的ca证书不被信任。手动信任就行了。

linux的话手动执行一下update-ca-trust试试看 (rhel)

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏