【问题标题】:GRPC ssl with self-signed cert带有自签名证书的 GRPC ssl
【发布时间】:2019-07-21 18:27:30
【问题描述】:

我正在尝试将自签名证书与 GRPC 一起使用。我生成了证书/密钥:

openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

这给了我两个文件:cert.pemkey.pem

我有一个 Kotlin GRPC 服务器,我设置如下:

val ca = classLoader.getResourceAsStream("cert.pem")
val key = classLoader.getResourceAsStream("key.pem")
ServerBuilder
    .forPort(8443)
    .useTransportSecurity(ca, key)
    .addService(...)
    .build()
    .start()

这似乎已成功启动。我有一个颤振客户端,我通过以下方式设置:

final cert = await rootBundle.load('cert.pem')
final certAsList = cert.buffer
        .asUint8List(
          cert.offsetInBytes,
          cert.lengthInBytes,
        )
        .map((uint8) => uint8.toInt())
        .toList()
final channel = new ClientChannel(
      'localhost',
      port: 8443,
      options: ChannelOptions(
        credentials: ChannelCredentials.secure(certificates: certAsList),
      ),
    )

但是,使用此通道连接到我的服务会出现以下错误:

gRPC Error (14, Error connecting: HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: ok(handshake.cc:352)))

这个设置有什么问题?

【问题讨论】:

  • 您找到解决此错误的好方法了吗?在我的颤振 grpc 客户端中得到完全相同的结果。
  • @codeKiller 看看我的回答

标签: ssl kotlin flutter dart grpc


【解决方案1】:

默认情况下,提供的证书(在任一方向)将通过多种方式进行验证:

  1. 主机名必须与证书中的主题公用名匹配 呈现。
  2. 不得通过使用 CRL 或 OCSP 验证
  3. 必须信任根 CA 证书,并且没有 可以撤销中介机构

您很可能遇到了#3,因为它是一个自签名证书(根本身是不受信任的)并且您已经在使用localhost 连接到它。您可以将此证书添加到受信任的 CA 证书存储中,也可以以编程方式为您的 SSL 上下文创建不安全的证书验证。有关 Kotlin (Java) 方面的更多详细信息,您可以在此处咨询 SO:Disabling certificate check in gRPC TLS

【讨论】:

    【解决方案2】:

    Matt's answer 中所述,运行 Flutter 应用的设备不信任您的 CA 证书,因为它是自签名的。

    现在你有两个选择:

    1. 从 Verisign 等证书颁发机构获取有效证书,或
    2. 在 Flutter 应用本身中禁用证书验证

    下面是实现选项 2 的方法。您只需将 BadCertificateHandler 添加到 ChannelCredentials 实例,如下所示:

        final cert = await rootBundle.load('cert.pem')
        final certAsList = cert.buffer
            .asUint8List(
          cert.offsetInBytes,
          cert.lengthInBytes,
        )
            .map((uint8) => uint8.toInt())
            .toList()
        final channel = new ClientChannel(
          'localhost',
          port: 8443,
          options: ChannelOptions(
            credentials: ChannelCredentials.secure(
              certificates: certAsList,
              onBadCertificate: (cert, host) => true, // <--- **** The missing part **** 
            ),
          ),
        )
    

    通过拥有一个始终返回true 的处理程序,您基本上完全禁用了证书验证。现在,您是否真的想这样做取决于您;)

    【讨论】:

      猜你喜欢
      • 2015-06-18
      • 2020-11-23
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      • 2016-06-06
      • 2019-04-26
      • 2015-03-06
      • 1970-01-01
      相关资源
      最近更新 更多