Flutter Dio HTTPS 证书验证忽略 onBadCertificate - CA 证书问题?

问题描述 投票:0回答:3

我遇到了一些进退两难的情况。我正在编写一个客户端/服务器应用程序。前端是Flutter,使用Dio http包,后端是Java。后端 REST API 通过 TLS 证书进行保护。

正如许多其他问题所指出的,Flutter 似乎无法访问所有平台上的系统 CA 证书存储。这是有问题的,因为我打算允许服务器应用程序的自托管,这意味着来自所有不同 CA 的证书都可以在服务器端使用,因此我的 HTTP 客户端将需要支持典型 Web 浏览器支持的所有 CA。

Dio 显然允许您设置可信的证书链,但我想知道如何最好地利用它。

有人遇到过这个问题吗?您采取了什么解决方案来解决这个问题?

这些是我到目前为止想到的解决方案:

  1. 允许用户“上传”ca 证书包并将字节存储在shared_preferences中(对用户来说很困难)
  2. 寻找另一种方法来验证证书,例如用户输入指纹? (不太困难,让所有证书都无法通过原始验证,然后使用 onBadCertificate 针对存储的指纹进行自定义验证)
  3. 查找提供系统证书存储访问权限的软件包
  4. 在应用程序内发送大多数知名 CA 证书,并以某种方式将它们信任给 Dio

我来这里的另一个问题是 Dio 似乎忽略了我的 onBadCertificate 方法。我在 ConnectionManager 中声明了这一点,我不应该这样做吗?

这是被忽略的代码:

var dio = Dio()
  ..options.baseUrl = server
  ..interceptors.add(LogInterceptor())
  ..interceptors.add(CookieManager(cookieJar))
  ..httpClientAdapter = Http2Adapter(
    ConnectionManager(
      idleTimeout: 10000,
      // Ignore bad certificate
      onClientCreate: (_, config) => {
        //config.context?.setTrustedCertificatesBytes(File("/assets/certs/wildcard.pem").readAsBytesSync()),
        config.onBadCertificate = (_) => true, // <-- ignored, should bypass check
      }
    ),
  );

编辑:

正如评论中提到的,Flutter 实际上能够使用系统 CA 证书存储。当我测试其他平台时,如果遇到任何证书问题,我会进行更新。不过这个已经解决了!

flutter dart ssl-certificate http2 dio
3个回答
4
投票

我也有同样的问题,因为在某些旧型号的手机上,用户会看到证书错误。所以,我找到了这个解决方案:

_dio = Dio(_baseOptions);

    //check bad certificate
    (_dio!.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (HttpClient client) {
      client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
      return client;
    };

https://github.com/flutterchina/dio/issues/32#issuecomment-487401443


2
投票

最终的核心问题是服务器没有提供完整的证书链,而只提供了叶证书。如果浏览器在其他地方看到中间证书,某些浏览器会隐藏此类问题。因此,仅仅因为浏览器中的操作正常,并不意味着服务器实际上为其他 TLS 客户端提供了足够的信息来验证证书链。

因此,解决方案是配置服务器以提供完整的证书链。


0
投票

截至 2024 年 3 月:

~~

onHttpClientCreate
~~ 回调已弃用。现在您应该使用
createHttpClient
并返回您自己的
HttpClient
实例:

Dio createDio({required String baseUrl, bool trustSelfSigned = false}) {
  // initialize dio
  final dio = Dio()
    ..options.baseUrl = baseUrl;

  // allow self-signed certificate
  (dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
    final client = HttpClient();
    client.badCertificateCallback = (cert, host, port) => trustSelfSigned;
    return client;
  };
  
  return dio;
}
© www.soinside.com 2019 - 2024. All rights reserved.