使用自签名证书实现GRPC SSL

7

我正在尝试在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()

看起来启动成功了。我有一个Flutter客户端,我是这样设置的:

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)))

这个设置有什么问题吗?

你找到了解决这个错误的好方法吗?我在我的Flutter gRPC客户端中也遇到了完全相同的问题。 - codeKiller
@codeKiller,请查看我的答案。 - Nimrod Dayan
2个回答

4

默认情况下,证书(双向认证或单向认证)将通过以下几种方式进行验证:

  1. 主机名必须与呈现的证书中的主题公共名称匹配
  2. 使用CRL或OCSP来验证证书是否已被吊销
  3. 根CA证书必须是受信任的,并且没有中间人证书被吊销

由于它是自签名证书(根证书是自己且不受信任),因此您可能会遇到第3种情况,并且已经在使用localhost进行连接。您可以将此证书添加到可信CA证书存储库中,或者可以编程方式为SSL上下文创建一个不安全的证书验证。有关Kotlin(Java)方面的更多详细信息,请参阅此处的SO:Disabling certificate check in gRPC TLS


1

Matt's answer中所述,由于您的CA证书是自签名的,因此设备无法信任运行Flutter应用程序的证书。

现在您有两个选择:

  1. 从像Verisign这样的证书颁发机构获取有效证书,或者
  2. 在Flutter应用程序本身中禁用证书验证

以下是实现第二个选项的方法。只需将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的处理程序,您基本上完全禁用了证书验证。现在,您是否真正想这样做取决于您自己;)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接