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

Android SSL握手错误:CertPathValidatorException信任锚未找到求助

问题:HTTPS请求突然失效,报Trust anchor for certification path not found错误

原本正常的HTTPS请求一周后突然失效,已获取站点PEM格式证书(也尝试过证书链),但仍持续出现错误:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

相关代码

建立HTTPS连接的工具方法

public static HttpsURLConnection setUpHttpsConnection(String urlString, Context ctx)
     {
         try
         {
             CertificateFactory cf = CertificateFactory.getInstance("X.509");
             InputStream caInput = new BufferedInputStream(ctx.getAssets().open("servercert.pem"));
             Certificate ca = cf.generateCertificate(caInput);
             System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());

             // Create a KeyStore containing our trusted CAs
             String keyStoreType = KeyStore.getDefaultType();
             KeyStore keyStore = KeyStore.getInstance(keyStoreType);
             keyStore.load(null, null);
             keyStore.setCertificateEntry("ca", ca);


             // Create a TrustManager that trusts the CAs in our KeyStore
             String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
             TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
             tmf.init(keyStore);
             

             // Create a TrustManager that trusts the CAs in our KeyStore
             String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
             TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
             tmf.init(keyStore);

             // Create an SSLContext that uses our TrustManager
             SSLContext context = SSLContext.getInstance("TLS");
             context.init(null, tmf.getTrustManagers(), null);

             

             // Tell the URLConnection to use a SocketFactory from our SSLContext
             URL url = new URL(urlString);
             URLEncoder.encode(url.toString(), "UTF-8");


             HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();

             urlConnection.setSSLSocketFactory(context.getSocketFactory());

             return urlConnection;
         }
         catch (Exception ex)
         {
             Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
             return null;
         }
    }

MainActivity中的调用代码

HttpsURLConnection myConnection = setUpHttpsConnection(endpoint.toString(), ctx);

//end point is - www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=NVDA&datatype=json&apikey=U89XCI9ILUCICTP1

//fails on the line below
 if (myConnection.getResponseCode() == 200) {
                InputStream responseBody = myConnection.getInputStream();

报错堆栈信息

W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
W/System.err:     at com.android.org.conscrypt.SSLUtils.toSSLHandshakeException(SSLUtils.java:362)
W/System.err:     at com.android.org.conscrypt.ConscryptEngine.convertException(ConscryptEngine.java:1134)
W/System.err:     at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1089)
W/System.err:     at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876)
W/System.err:     at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747)
W/System.err:     at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712)
W/System.err:     at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:849)
W/System.err:     at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.access$100(ConscryptEngineSocket.java:722)
W/System.err:     at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:238)

已配置networkconfig.xml指向证书,并设置了Manifest文件,但仍反复出现相同错误,请求帮助解决。


解决方案

1. 确保证书包含完整信任链

只导入服务器证书通常无法通过验证,需要获取从服务器证书到根CA的完整证书链。可以用以下命令提取目标站点的完整证书链:

openssl s_client -connect www.alphavantage.co:443 -showcerts

将输出中所有-----BEGIN CERTIFICATE-----到-----END CERTIFICATE-----的块按顺序(服务器证书→中间CA→根CA)复制到servercert.pem文件中。

2. 修复代码冗余与无效逻辑

代码中重复创建了TrustManagerFactory实例,且URLEncoder.encode(url.toString(), "UTF-8")属于无效逻辑(未使用编码结果,还可能引发异常),直接删除。修改后的工具方法:

public static HttpsURLConnection setUpHttpsConnection(String urlString, Context ctx) {
    try {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = new BufferedInputStream(ctx.getAssets().open("servercert.pem"));
        Certificate ca = cf.generateCertificate(caInput);
        System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());

        // 初始化KeyStore并添加证书
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // 创建TrustManager
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // 初始化SSLContext
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);

        // 建立连接
        URL url = new URL(urlString);
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setSSLSocketFactory(context.getSocketFactory());
        // 强制主机名验证,防止中间人攻击
        urlConnection.setHostnameVerifier((hostname, session) -> hostname.equals("www.alphavantage.co"));

        return urlConnection;
    } catch (Exception ex) {
        Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
        return null;
    }
}

3. 核对network_security_config配置

如果使用该配置,需确保证书放在res/raw目录下,且配置文件正确:

<!-- res/xml/network_security_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">www.alphavantage.co</domain>
        <trust-anchors>
            <certificates src="@raw/servercert"/>
            <!-- 若需保留系统信任CA,添加此行 -->
            <!-- <certificates src="system"/> -->
        </trust-anchors>
    </domain-config>
</network-security-config>

并在Manifest中声明:

<application ... android:networkSecurityConfig="@xml/network_security_config">

4. 确认服务器证书状态

请求突然失效大概率是服务器更换了SSL证书,或中间CA证书过期。重新获取最新的证书链导入即可。

5. 调试验证

可以在代码中添加日志,打印加载的证书信息,或使用Android Studio的Network Inspector查看SSL握手细节,确认证书是否被正确识别。

内容的提问来源于stack exchange,提问作者SunnyCoder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 02:24:52