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

Dart HTTPS请求报CERTIFICATE_VERIFY_FAILED 已信任证书仍报错

触发badCertificateCallback的核心原因

这个问题是Intel芯片macOS Monterey环境下,Dart HTTPS客户端的平台特有行为导致的,和你传入的证书内容正确性无关:

  • macOS版本的Dart在做TLS证书校验时,会优先调用系统原生Security Framework完成校验流程,不会直接读取你通过SecurityContext.setTrustedCertificatesBytes传入的自定义受信任证书列表
  • 你设置withTrustedRoots: false仅会屏蔽Dart内置的根证书列表,不会阻断系统层的证书校验逻辑。只要系统层判定证书不受信任,不管你有没有在自定义Context里加入对应证书,都会直接触发badCertificateCallback
  • 你在回调里做的PEM字符串相等校验返回true,已经可以证明服务端返回的证书和你本地持有的可信证书内容完全一致,证书传输、内容匹配环节没有问题,问题出在Dart的信任校验流程没走到你自定义的信任列表这一步。
排查修复方案
  • 先修正主机名匹配问题:你先后用127.0.0.1、localhost作为请求地址,注意自签证书的CN/SAN字段必须和请求的Host完全匹配。你后来生成的证书CN是localhost,就不要用127.0.0.1发起请求,否则主机名校验不通过也会触发回调。
  • 绕过平台校验逻辑的影响:不要完全依赖SecurityContext的信任设置,在badCertificateCallback中实现严格的自定义校验即可,不要无脑返回true避免中间人攻击。推荐提前计算可信证书的SHA256指纹,回调中比对证书指纹,比直接比对PEM字符串更稳定:
import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:collection/collection.dart';

// 工具方法:PEM格式证书转DER二进制
List<int> pemToDer(List<int> pemBytes) {
  final pemStr = String.fromCharCodes(pemBytes).trim();
  final base64Str = pemStr
      .replaceAll('-----BEGIN CERTIFICATE-----', '')
      .replaceAll('-----END CERTIFICATE-----', '')
      .replaceAll('\n', '')
      .replaceAll('\r', '');
  return base64Decode(base64Str);
}

void main() {
  final trustedPem = File('../server_keys/cert.pem').readAsBytesSync();
  final trustedCertFingerprint = sha256.convert(pemToDer(trustedPem)).bytes;

  SecurityContext context = SecurityContext(withTrustedRoots: false);
  final httpClient = HttpClient(context: context);
  httpClient.badCertificateCallback = (cert, host, port) {
    // 先校验主机名
    if (host != 'localhost') return false;
    // 再校验证书指纹
    final currentCertFingerprint = sha256.convert(cert.der).bytes;
    return const ListEquality().equals(trustedCertFingerprint, currentCertFingerprint);
  };
}
  • 你也可以做对照验证:把自签证书导入macOS钥匙串并设置为「始终信任」,再运行原始代码就会发现badCertificateCallback不再触发,这也能印证Dart在macOS下优先读取系统钥匙串的信任规则,没有优先使用你传入Context的自定义证书。
curl正常访问的原因

curl默认使用OpenSSL/LibreSSL作为TLS实现,不会调用macOS系统安全框架,会直接读取你通过--cacert参数传入的证书完成校验,所以不会触发这个平台特有问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:54:22