如何在Grpc.Core中忽略服务器证书有效性校验?
问题背景
尝试多种方式建立gRPC SSL连接均失败,初始代码如下:
var httpClientHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }; var httpClientHandler = new HttpClientHandler(); var certBytes = Encoding.ASCII.GetBytes(cert); httpClientHandler.ClientCertificates.Add(new X509Certificate2(certBytes)); var httpClient = new HttpClient(httpClientHandler); var creds = new SslCredentials("", null, (context) => true); GrpcChannel.ForAddress(host, new GrpcChannelOptions() { HttpClient = httpClient, Credentials = creds })
触发错误:
Grpc.Core.RpcException: Status(StatusCode="Internal", Detail="Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: PartialChain", DebugException="System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.") ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: PartialChain at System.Net.Security.SslStream.SendAuthResetSignal(ReadOnlySpan`1 alert, ExceptionDispatchInfo exception) at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions) at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken) at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken)
更新后尝试以下代码,错误仍未解决:
var creds = new SslCredentials(null, null, (context) => true); grpc = new Service.Client( GrpcChannel .ForAddress(host, new GrpcChannelOptions() { Credentials = creds }) .Intercept(new GrpcAuthHeaderInterceptor(authHash)) );
解决方案
1. 修复证书链完整性
PartialChain错误核心是客户端无法验证服务端证书的完整信任链,可按以下步骤处理:
- 用
openssl s_client -connect <host>:<port>命令检查服务端返回的证书链是否包含中间证书和根证书。 - 如果链不完整,将根证书和中间证书合并为一个PEM文件,在创建
SslCredentials时传入:
// fullChainPem是包含根证书+中间证书的字符串 var creds = new SslCredentials(fullChainPem, null, (context, cert, chain, errors) => true);
2. 统一验证逻辑,避免冲突
你同时配置了HttpClientHandler和gRPCSslCredentials的验证回调,两者会互相干扰,建议二选一:
方案A:仅用HttpClientHandler跳过验证(测试环境)
var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (_, _, _, _) => true }; var channel = GrpcChannel.ForAddress(host, new GrpcChannelOptions { HttpClient = new HttpClient(handler) }); grpc = new Service.Client(channel).Intercept(new GrpcAuthHeaderInterceptor(authHash));
方案B:用SslCredentials自定义验证
// 若需信任自定义根证书,传入根证书PEM内容 var rootCertContent = File.ReadAllText("root_ca.pem"); var creds = new SslCredentials(rootCertContent, null, (context, cert, chain, errors) => { // 生产环境请替换为实际验证逻辑,测试环境可直接返回true return true; }); var channel = GrpcChannel.ForAddress(host, new GrpcChannelOptions { Credentials = creds }); grpc = new Service.Client(channel).Intercept(new GrpcAuthHeaderInterceptor(authHash));
3. 修正客户端证书加载方式
如果需要客户端证书认证,不要用Encoding.ASCII.GetBytes加载证书,证书应为二进制或PFX格式:
// 加载带私钥的PFX客户端证书 var clientCert = new X509Certificate2("client_cert.pfx", "cert_password"); var handler = new HttpClientHandler { ClientCertificates = { clientCert }, ServerCertificateCustomValidationCallback = (_, _, _, _) => true }; var channel = GrpcChannel.ForAddress(host, new GrpcChannelOptions { HttpClient = new HttpClient(handler) });
4. 检查版本兼容性
确保Grpc.Net.Client版本与你的.NET版本匹配,版本不兼容可能导致SSL验证逻辑异常。
内容的提问来源于stack exchange,提问作者iluxa1810

