Android 5.1发起POST请求报HandshakeException证书错误如何解决
问题根因
Android 7.0(API级别24)及以下版本的系统内置根证书库不会随系统更新迭代,2021年Let's Encrypt旧根证书DST Root CA X3正式过期后,Android 5.1这类低版本系统没有内置信任新的ISRG Root X1根证书,应用发起HTTPS POST请求校验证书链时就会抛出证书过期的握手异常;Android 10及以上版本系统内置了新版根证书,因此不会触发该报错。
可落地修复方案
方案1:客户端内置信任新根证书(正式环境推荐,无安全风险)
该方案不会降低HTTPS请求的安全等级,适配所有低版本Android系统:
- 在项目安卓模块的
app/src/main/res/路径下新建raw目录,将下载好的ISRG Root X1根证书PEM格式文件放入该目录,文件命名为isrgrootx1.pem - 在
app/src/main/res/路径下新建xml目录,在目录内创建network_security_config.xml配置文件,写入如下内容:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="false"> <trust-anchors> <!-- 信任内置的ISRG根证书 --> <certificates src="@raw/isrgrootx1" /> <!-- 保留系统原有信任的根证书 --> <certificates src="system" /> </trust-anchors> </base-config> </network-security-config>
- 打开同路径下的
AndroidManifest.xml文件,在<application>标签中添加属性关联上述安全配置:
<application android:networkSecurityConfig="@xml/network_security_config" <!-- 其余原有配置项保持不变即可 --> >
- 如果是Flutter项目,需要兼容API 24以下版本的话,额外将
isrgrootx1.pem放到项目的assets目录下,在pubspec.yaml中配置资源引用后,在main函数启动时先加载证书到全局安全上下文:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 加载内置的信任根证书 ByteData certData = await rootBundle.load('assets/certs/isrgrootx1.pem'); SecurityContext.defaultContext.setTrustedCertificatesBytes( certData.buffer.asUint8List() ); runApp(const MyApp()); }
- 全量重新编译打包应用,安装到低版本系统上即可正常发起HTTPS请求。
方案2:服务端调整证书链(无需客户端发版)
如果你有后端服务的配置权限,可以在服务端部署SSL证书时,补充完整的交叉签名证书链,兼容旧系统的证书校验逻辑,用户不需要更新客户端就能恢复正常访问。
方案3:临时绕过证书校验(仅开发调试可用,禁止线上发布)
Flutter开发场景下可以通过重写HTTP客户端的证书校验逻辑临时绕过报错,仅适合本地调试阶段使用:
class DevHttpOverrides extends HttpOverrides { @override HttpClient createHttpClient(SecurityContext? context) { return super.createHttpClient(context) ..badCertificateCallback = (X509Certificate cert, String host, int port) => true; } } void main() { // 调试阶段初始化全局HTTP覆盖 HttpOverrides.global = DevHttpOverrides(); runApp(const MyApp()); }
警告:该方案会完全跳过HTTPS证书合法性校验,存在被中间人攻击窃取请求数据的极高风险,绝对不能在正式对外发布的安装包中使用。
内容的提问来源于stack exchange,提问作者Karol Wiśniewski
相关产品推荐
相关产品推荐

