Dart gRPC客户端与ASP.NET服务器TLS认证遇未知连接终止错误求助
问题背景
尝试为与ASP.NET服务器通信的Dart gRPC客户端实现TLS认证,客户端配置如下:
final channel = ClientChannel(hostname, port: port, options: ChannelOptions( credentials: ChannelCredentials.secure( onBadCertificate: (cert,host) => true )));
预期服务器会拒绝客户端认证,但调用接口时Dart抛出错误:
[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: gRPC Error (code: 2, codeName: UNKNOWN, message: HTTP/2 error: Connection error: Connection is being forcefully terminated. (errorCode: 10), details: null, rawResponse: null, trailers: {})
服务器无任何日志输出。但浏览器访问https://localhost:5400能得到预期的客户端证书拒绝提示,C#客户端连接认证正常,非安全连接也能正常工作。WireShark抓包显示服务器发送Encrypted Alert后强制关闭连接。
排查建议
补全客户端证书配置
当前ChannelCredentials.secure()仅设置了onBadCertificate,但如果服务器要求客户端证书认证,Dart客户端不会自动加载客户端证书(浏览器、C#客户端可能已配置系统级或指定证书)。需显式提供客户端证书链和私钥:final channel = ClientChannel(hostname, port: port, options: ChannelOptions( credentials: ChannelCredentials.secure( certificates: await rootBundle.load('assets/client_cert.pem'), privateKey: await rootBundle.load('assets/client_key.pem'), onBadCertificate: (cert, host) => true, ), ), );确保证书文件路径正确,格式为PEM。
启用Dart gRPC详细日志
在客户端初始化前添加日志配置,捕获TLS握手阶段的具体错误:import 'package:grpc/grpc.dart'; import 'package:grpc/src/shared/logging.dart'; void main() { Logger.root.level = Level.ALL; Logger.root.onRecord.listen((record) { print('${record.level.name}: ${record.time}: ${record.message}'); }); // 后续客户端初始化代码 }日志会暴露TLS握手时的具体问题,比如证书不被信任、缺少客户端证书等。
对齐TLS版本与加密套件
检查ASP.NET服务器支持的TLS版本和加密套件,显式指定Dart客户端的兼容配置:final channel = ClientChannel(hostname, port: port, options: ChannelOptions( credentials: ChannelCredentials.secure( onBadCertificate: (cert, host) => true, tlsVersion: TlsVersion.tls1_2, cipherSuites: [ 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256', ], ), ), );对比浏览器、C#客户端使用的加密套件,确保匹配。
开启服务器端详细日志
修改ASP.NET服务器的appsettings.json,启用TLS和gRPC的调试日志:{ "Logging": { "LogLevel": { "Microsoft.AspNetCore.Server.Kestrel": "Debug", "Microsoft.AspNetCore.Http.Connections": "Debug", "Grpc.AspNetCore.Server": "Debug" } } }这能捕获服务器端TLS握手时的错误,比如客户端证书无效、证书链不完整等。
验证SNI与证书域名匹配
WireShark抓包显示客户端Hello包含SNI=localhost,确保服务器证书的SAN/CN字段包含localhost,或调整Dart客户端的hostname参数与证书域名一致。
内容的提问来源于stack exchange,提问作者George Gayton

