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

Android Studio中HttpsURLConnection连接IIS服务器遇证书信任锚缺失错误

解决HttpsURLConnection连接IIS服务器的SSLHandshakeException问题

问题原因

Android系统默认信任的CA列表中不包含IIS服务器证书的签发机构,或者服务器证书链不完整,导致系统无法验证证书合法性,从而抛出Trust anchor for certification path not found错误。连接Ngrok正常是因为其证书由公共可信CA签发,已在系统信任列表内。

解决方案

方式一:导入CER证书配置自定义信任管理器

适用于仅需验证服务器证书的场景:

  1. 将.cer证书文件放入项目app/src/main/res/raw目录(无raw文件夹则新建)。
  2. 创建自定义信任管理器类加载证书:
import android.content.Context;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

public class CustomTrustManager {
    public static SSLContext getSSLContext(Context context) throws Exception {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream certInputStream = context.getResources().openRawResource(R.raw.your_cert_name); // 替换为证书文件名(不带.cer后缀)
        X509Certificate cert = (X509Certificate) cf.generateCertificate(certInputStream);
        certInputStream.close();

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry("server_cert", cert);

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);
        return sslContext;
    }
}
  1. 修改原HttpsURLConnection代码,应用自定义SSL上下文:
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
// 添加自定义SSL套接字工厂配置
try {
    SSLContext sslContext = CustomTrustManager.getSSLContext(getApplicationContext());
    connection.setSSLSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
    e.printStackTrace();
}
// 原有代码保持不变
connection.setConnectTimeout(15000);
HashMap<String, String> paramss = new HashMap<String, String>();
paramss.put("grant_type", "password");
paramss.put("username", prefer.getString("ws_sq_user",""));
paramss.put("password", prefer.getString("ws_sq_pwd",""));
// ... 其余参数拼接、请求发送代码

方式二:使用PFX证书(适用于双向SSL认证场景)

如果PFX证书包含客户端私钥,可按以下方式加载:

import android.content.Context;
import java.io.InputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

public class PFXSSLUtil {
    public static SSLContext getSSLContext(Context context, String pfxPassword) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        InputStream pfxInputStream = context.getResources().openRawResource(R.raw.your_pfx_name); // 替换为PFX文件名(不带.pfx后缀)
        keyStore.load(pfxInputStream, pfxPassword.toCharArray());
        pfxInputStream.close();

        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, pfxPassword.toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        return sslContext;
    }
}

同样在连接代码中设置套接字工厂:

HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
try {
    SSLContext sslContext = PFXSSLUtil.getSSLContext(getApplicationContext(), "your_pfx_password"); // 替换为PFX证书密码
    connection.setSSLSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
    e.printStackTrace();
}
// 后续代码不变

额外注意事项

  • 验证证书完整性:可通过openssl x509 -in your_cert.cer -text -noout命令检查证书是否有效。
  • 检查服务器证书链:若服务器缺失中间证书,需补充完整证书链后重新导入,或在IIS端配置完整证书链。
  • 禁止生产环境使用忽略SSL校验的代码,避免安全风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:13:14