【问题标题】:Self-signed cert for gRPC on FlutterFlutter 上 gRPC 的自签名证书
【发布时间】:2020-01-16 01:28:27
【问题描述】:

我有一个使用 gRPC 与服务器通信的 Flutter 应用程序。服务器正在为 TLS 使用自签名证书。我已将证书添加到我的 Flutter 应用程序中,这适用于 Android。但是在 iOS 上我得到 CERTIFICATE_VERIFY_FAILED 错误。 iOS 只是不允许自签名证书吗?

我正在按如下方式设置我的 gRPC 客户端:

    var cert = await rootBundle.load('assets/cert.crt');
    var creds = ChannelCredentials.secure(
        certificates: cert.buffer.asUint8List().toList()
    );
    var channel = ClientChannel(
        host,
        port: port,
        options: new ChannelOptions(credentials: creds));
    return GrpcClient(channel);

【问题讨论】:

    标签: ssl flutter dart grpc self-signed


    【解决方案1】:

    在 iOS 上似乎没有明显的解决方案来添加受信任的自签名根 CA。由于生产环境可能有一个公开信任的 CA,您可以通过禁用 TLS 验证来解决

    这是我full example repo的相关sn-p:

    Future<ClientChannel> makeChannel() async {
      final caCert = await rootBundle.loadString('assets/pki/ca/ca.crt');
    
      return ClientChannel(
        'localhost',
        port: 13100,
        options: ChannelOptions(
          credentials: ChannelCredentials.secure(
            certificates: utf8.encode(caCert),
    
            // --- WORKAROUND FOR SELF-SIGNED DEVELOPMENT CA ---
            onBadCertificate: (certificate, host) => host == 'localhost:13100',
          ),
        ),
      );
    }
    

    在这种情况下,我的服务器正在监听localhost:13100

    【讨论】:

    • 谢谢,这基本上就是我最终所做的。
    • 嘿@AndiDog,我的应用程序的行为会有所不同,具体取决于我是否添加onBadCertificate...没有它,我得到:CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate,有了它,我得到:SSLV3_ALERT_BAD_CERTIFICATE.. .both 相同的.perm 文件....任何线索可能是错误的?
    • 在 Wireshark 或日志中调试警报?既然您看到了差异,我假设所需的效果确实有效,但您可能仍因某些其他原因(例如错误的客户端证书)收到服务器端警报。
    • @JamesTan 没有。但是哪个 Flutter 平台运行节点?您是否将服务器端 Dart 代码交叉编译到 node.js?那么也许stackoverflow.com/questions/10888610/… 有帮助。
    • 对不起,我使用 nodejs 作为客户端,而不是颤振。没有尝试过那个参考,但我得到了这个工作:stackoverflow.com/questions/62108009/…
    【解决方案2】:

    以下内容改编自: https://github.com/grpc/grpc-dart/issues/134

    它允许指定自定义(或自签名)CA 证书、客户端证书和/或自定义域:

    import 'dart:convert';
    import 'dart:io';
    import 'package:grpc/grpc.dart';
    
    
    class CustomChannelCredentials extends ChannelCredentials {
      final String caCert;
      final String? clientCert;
      final String? clientKey;
    
      const CustomChannelCredentials({
        required this.caCert,
        this.clientCert,
        this.clientKey,
        String? authority, // Custom domain used by server cert
      }) : super.secure(authority: authority);
    
      @override
      SecurityContext get securityContext {
        final context = SecurityContext(
          withTrustedRoots: false, // We want to specify a custom CA cert
        );
        context.setTrustedCertificatesBytes(utf8.encode(caCert));
        context.setAlpnProtocols(supportedAlpnProtocols, false);
    
        if (clientCert != null) {
          context.useCertificateChainBytes(utf8.encode(clientCert!));
        }
        if (clientKey != null) {
          context.usePrivateKeyBytes(utf8.encode(clientKey!));
        }
        return context;
      }
    }
    

    示例用法:

    final channel = ClientChannel(
     serverAddress,
      port: serverPort,
      options: ChannelOptions(
        credentials: CustomChannelCredentials(
          caCert: selfSignedCaCertPem,
          // clientCert: clientCertPem,
          // clientKey: clientKeyPem,
          authority: 'localhost',
        ),
      ),
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-24
      • 1970-01-01
      • 2022-10-25
      • 1970-01-01
      • 2018-02-18
      • 2020-10-28
      • 2018-05-11
      • 1970-01-01
      相关资源
      最近更新 更多