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

Android 9(API 28)中HttpsURLConnection失效,抛出SSLPeerUnverifiedException

嘿,这个问题我之前帮不少开发者排查过,Android 9(API 28)下用HttpsURLConnection触发SSLPeerUnverifiedException,大多和系统默认安全配置变化或者证书信任逻辑有关,我给你拆解下核心原因和对应的解决办法:

常见原因1:Android 9默认限制了TLS版本

Android 9开始,系统默认只允许使用TLS 1.2及以上版本的加密协议,如果你的服务器还在使用旧的TLS 1.0/1.1,就会触发这个异常。

临时兼容方案(不推荐生产环境)

如果暂时没法升级服务器,可以通过自定义SSLSocketFactory让HttpsURLConnection支持旧版本协议:

// 创建支持多版本TLS的SSL上下文
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, new SecureRandom());

// 包装原生SSLSocketFactory,启用旧协议
SSLSocketFactory socketFactory = new SSLSocketFactoryCompat(sslContext.getSocketFactory());

// 配置到HttpsURLConnection
HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();
connection.setSSLSocketFactory(socketFactory);
// 后续操作...
connection.connect();

对应的SSLSocketFactoryCompat实现:

public class SSLSocketFactoryCompat extends SSLSocketFactory {
    private final SSLSocketFactory delegate;

    public SSLSocketFactoryCompat(SSLSocketFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableOldTlsProtocols((SSLSocket) delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableOldTlsProtocols((SSLSocket) delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableOldTlsProtocols((SSLSocket) delegate.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableOldTlsProtocols((SSLSocket) delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableOldTlsProtocols((SSLSocket) delegate.createSocket(address, port, localAddress, localPort));
    }

    private Socket enableOldTlsProtocols(SSLSocket socket) {
        // 启用TLS 1.0、1.1、1.2
        socket.setEnabledProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"});
        return socket;
    }
}

注意:这个方案只是临时过渡,强烈建议优先升级服务器到TLS 1.2+,旧协议存在安全漏洞。

常见原因2:服务器证书不被系统信任

如果服务器用的是自签名证书,或者证书链不完整(缺少中间证书),Android系统会拒绝信任该证书,从而触发异常。

测试环境临时方案(绝对禁止生产环境使用)

如果只是本地测试,可以临时跳过证书验证(会完全失去HTTPS的安全防护,仅用于测试):

// 创建信任所有证书的TrustManager
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }
};

// 初始化SSL上下文
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new SecureRandom());

// 配置HttpsURLConnection
HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
// 跳过主机名验证
connection.setHostnameVerifier((hostname, session) -> true);

connection.connect();

生产环境正确方案:导入自定义证书信任库

把服务器的合法证书(.crt/.pem格式)放到app/src/main/res/raw目录,然后通过自定义TrustManager让应用信任该证书:

// 加载raw目录下的证书文件
InputStream certInputStream = getResources().openRawResource(R.raw.your_server_cert);

// 解析证书
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(certInputStream);
certInputStream.close();

// 创建KeyStore并添加证书
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server_cert", cert);

// 初始化TrustManagerFactory
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);

// 创建SSL上下文
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());

// 配置到HttpsURLConnection
HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());

connection.connect();
总结

优先推荐的解决顺序是:

  1. 升级服务器到TLS 1.2+,确保证书链完整且被权威CA签发
  2. 生产环境使用自定义证书信任库方案
  3. 仅测试环境使用跳过验证的临时方案

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:10:59