Flutter 上 gRPC 的自签名证书
Self-signed cert for gRPC on Flutter
我有一个使用 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);
iOS 上似乎没有明显的解决方案来添加受信任的自签名根 CA。由于生产可能有一个公开信任的 CA,您可以通过禁用 TLS 开发验证来解决 only.
这是我的 full example repo 的相关片段:
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
。
以下改编自:
https://github.com/grpc/grpc-dart/issues/134
它允许指定自定义(或 self-signed)CA 证书、客户端证书、and/or 自定义域:
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',
),
),
);
我有一个使用 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);
iOS 上似乎没有明显的解决方案来添加受信任的自签名根 CA。由于生产可能有一个公开信任的 CA,您可以通过禁用 TLS 开发验证来解决 only.
这是我的 full example repo 的相关片段:
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
。
以下改编自: https://github.com/grpc/grpc-dart/issues/134
它允许指定自定义(或 self-signed)CA 证书、客户端证书、and/or 自定义域:
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',
),
),
);