Android Studio中HttpsURLConnection连接IIS服务器遇证书信任锚缺失错误
解决HttpsURLConnection连接IIS服务器的SSLHandshakeException问题
问题原因
Android系统默认信任的CA列表中不包含IIS服务器证书的签发机构,或者服务器证书链不完整,导致系统无法验证证书合法性,从而抛出Trust anchor for certification path not found错误。连接Ngrok正常是因为其证书由公共可信CA签发,已在系统信任列表内。
解决方案
方式一:导入CER证书配置自定义信任管理器
适用于仅需验证服务器证书的场景:
- 将
.cer证书文件放入项目app/src/main/res/raw目录(无raw文件夹则新建)。 - 创建自定义信任管理器类加载证书:
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; } }
- 修改原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
相关产品推荐
相关产品推荐

