Flutter 如何为http包请求添加证书校验以实现SSL HTTPS连接
Dart http包实现HTTPS证书校验的落地方案
核心实现逻辑
http包本身不直接在请求对象层提供证书校验的挂载入口,所有HTTPS证书校验逻辑都绑定在底层TCP连接建立阶段,需要通过自定义可复用的Client实例注入校验规则,不能直接在MultipartRequest的代码块位置插入校验逻辑。
常见的证书校验场景分为两类:
- 服务端使用公共可信CA签发的证书:系统会默认完成完整的证书链校验、域名匹配、有效期校验,不需要额外编写自定义代码即可正常建立加密连接
- 服务端使用自签证书、或需要通过证书钉扎提升安全性的场景:需要将服务端证书打包进应用安装包,通过自定义安全上下文、证书校验回调实现强校验
适配现有业务代码的改造步骤
- 提前将服务端的PEM格式证书文件放置到项目的
assets/certs/目录下,在pubspec.yaml中完成assets路径声明 - 封装带证书校验逻辑的自定义Client实例,替换默认的直连客户端
- 发送Multipart请求时,将自定义Client实例传入请求发送方法,确保请求走带校验逻辑的连接通道
参考实现代码
首先封装带校验逻辑的客户端初始化方法:
import 'dart:io'; import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:http/io_client.dart'; Future<http.Client> initSecureHttpsClient() async { // 加载应用内置的服务端证书到系统安全上下文 final serverCertBytes = await File('assets/certs/mywebsite_server.crt').readAsBytes(); final secureContext = SecurityContext.defaultContext ..setTrustedCertificatesBytes(serverCertBytes); // 配置底层HttpClient的证书校验回调 final rawHttpClient = HttpClient(context: secureContext) ..badCertificateCallback = (X509Certificate cert, String host, int port) { // 自定义校验规则:匹配目标域名、校验证书主体信息 final isTargetHost = host == 'www.mywebsite.com'; final isCertMatch = cert.subject.contains('O=MyWebsite Inc'); // 所有校验条件满足才放行连接 return isTargetHost && isCertMatch; }; // 将底层HttpClient包装为http包可识别的Client实例 return IOClient(rawHttpClient); }
替换原有请求逻辑,接入自定义带校验的客户端:
Future<void> sendLookupRequest() async { String url = "https://www.mywebsite.com"; print("Firing off url: ${url}"); // 初始化带证书校验的客户端 final secureClient = await initSecureHttpsClient(); var request = http.MultipartRequest("POST", Uri.parse(url)); // 保留原有POST字段逻辑 request.fields["lookup"] = "true"; request.fields["email"] = "blah@test.com"; request.fields["user_id"] = "1337"; // 传入自定义客户端发送请求 var response = await request.send(secureClient); var responseData = await response.stream.toBytes(); var responseString = String.fromCharCodes(responseData); print('================================'); print("response was: ${responseString}"); if (response.statusCode == 200) { var json_data = json.decode(responseString); for (var u in json_data) { print(u["response"]); } } // 请求完成后释放客户端连接资源 secureClient.close(); }
关键注意事项
- 严禁在
badCertificateCallback中直接写死返回true,该写法会完全跳过所有HTTPS安全校验,存在被中间人攻击窃取明文数据的重大风险 - 证书校验逻辑建议补充证书公钥指纹的比对,仅靠域名匹配的校验无法完全防范CA被篡改带来的安全风险
- 如果服务端使用公共可信CA签发的证书,不需要手动加载自定义证书文件,仅在回调中补充必要的指纹校验即可
内容的提问来源于stack exchange,提问作者Petro
相关产品推荐
相关产品推荐

