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

Android 7.0(Nougat)SSL握手信任锚缺失问题解决方案咨询

解决Android 7.0上Retrofit请求Railway后端的证书验证错误

问题根源

Android 7.0(API 24)及更早版本的系统信任存储未包含Railway平台SSL证书依赖的现代根CA证书,导致证书链验证失败,抛出java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.。

解决方案

方案1:添加根证书到应用信任存储(推荐,生产环境可用)

将Railway域名对应的根证书打包到应用中,让Retrofit使用自定义信任管理器完成验证:

  1. 获取根证书:用浏览器访问你的后端接口,查看证书详情,导出根证书(格式选PEM,重命名为ca.crt),放到app/src/main/res/raw目录。
  2. 实现自定义信任管理器:
import android.content.Context
import java.io.InputStream
import java.security.KeyStore
import java.security.cert.CertificateFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager

fun getCustomTrustManager(context: Context): X509TrustManager {
    val certFactory = CertificateFactory.getInstance("X.509")
    val certificate = context.resources.openRawResource(R.raw.ca).use { stream ->
        certFactory.generateCertificate(stream)
    }

    val keyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
        load(null, null)
        setCertificateEntry("railway_root_ca", certificate)
    }

    val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply {
        init(keyStore)
    }

    return trustManagerFactory.trustManagers.first() as X509TrustManager
}

fun getCustomSSLSocketFactory(context: Context): javax.net.ssl.SSLSocketFactory {
    val trustManager = getCustomTrustManager(context)
    val sslContext = SSLContext.getInstance("TLS").apply {
        init(null, arrayOf(trustManager), java.security.SecureRandom())
    }
    return sslContext.socketFactory
}
  1. 配置Retrofit使用自定义客户端:
val okHttpClient = OkHttpClient.Builder()
    .sslSocketFactory(getCustomSSLSocketFactory(context), getCustomTrustManager(context))
    .build()

val retrofit = Retrofit.Builder()
    .baseUrl("你的后端BaseUrl")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

方案2:兼容TLS协议配置(辅助方案)

Android 7.0默认对TLS 1.3支持有限,若后端强制使用TLS 1.3,可通过OkHttp配置兼容:

val okHttpClient = OkHttpClient.Builder()
    .connectionSpecs(listOf(
        ConnectionSpec.MODERN_TLS,
        ConnectionSpec.COMPATIBLE_TLS
    ))
    .build()

此方案需配合方案1使用,单独使用可能无法解决根证书缺失问题。

方案3:禁用证书验证(仅测试环境使用)

仅用于临时测试,生产环境绝对禁止(存在中间人攻击风险):

fun getUnsafeOkHttpClient(): OkHttpClient {
    return try {
        val trustAllCerts = arrayOf<X509TrustManager>(object : X509TrustManager {
            override fun checkClientTrusted(chain: Array<out java.security.cert.X509Certificate>?, authType: String?) = Unit
            override fun checkServerTrusted(chain: Array<out java.security.cert.X509Certificate>?, authType: String?) = Unit
            override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> = emptyArray()
        })

        val sslContext = SSLContext.getInstance("TLS").apply {
            init(null, trustAllCerts, java.security.SecureRandom())
        }

        OkHttpClient.Builder()
            .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0])
            .hostnameVerifier { _, _ -> true }
            .build()
    } catch (e: Exception) {
        throw RuntimeException(e)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:50:57