带客户端证书的.NET HttpClient在Linux下异常,求排查方案
我的请求配置代码如下:
var url = "https://api.the.url.com/path/ver/endpoint"; var certFile = "TheFile.pfx"; var certPass = "ThePassword"; var cert = new X509Certificate2( Path.Combine(AppContext.BaseDirectory, certFile), certPass, X509KeyStorageFlags.MachineKeySet); var handler = new SocketsHttpHandler(); handler.SslOptions.ClientCertificates = new X509CertificateCollection(); handler.SslOptions.ClientCertificates.Add(cert); handler.SslOptions.LocalCertificateSelectionCallback = (_,_,_,_,_) => cert; var httpClient = HttpClientFactory.Create(handler); var result = await httpClient.GetAsync(url); result.EnsureSuccessStatusCode();
该请求在Windows上偶尔失败,在Linux上则始终失败,错误信息:
The SSL connection could not be established, see inner exception.
Unable to write data to the transport connection: Connection reset by peer.
Connection reset by peer
TCP流量分析显示,客户端ACK服务器的Server Key Exchange/Server Hello Done后,握手就停止了,Windows抓包内容如下:
TCP 66 44222 → 443 [SYN, ECE, CWR] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM TCP 66 443 → 44222 [SYN, ACK, ECE] Seq=0 Ack=1 Win=14600 Len=0 MSS=1436 WS=1 SACK_PERM TCP 54 44222 → 443 [ACK] Seq=1 Ack=1 Win=262656 Len=0 TLSv1.2 328 Client Hello TCP 60 443 → 44222 [ACK] Seq=1 Ack=275 Win=14874 Len=0 TLSv1.2 1514 Server Hello TCP 1514 443 → 44222 [ACK] Seq=1461 Ack=275 Win=14874 Len=1460 [TCP segment of a reassembled PDU] TCP 54 44222 → 443 [ACK] Seq=275 Ack=2921 Win=262656 Len=0 TLSv1.2 1514 Certificate, Server Key Exchange TLSv1.2 360 Certificate Request, Server Hello Done TCP 54 44222 → 443 [ACK] Seq=275 Ack=4687 Win=262656 Len=0 TCP 109 443 → 44222 [RST, ACK] Seq=4687 Ack=275 Win=0 Len=55
正常情况下,此时应该收到以下内容而非RST, ACK:
TLSv1.2 2043 Certificate, Client Key Exchange, Certificate Verify, Change Cipher Spec, Encrypted Handshake Message TCP 60 443 → 44566 [ACK] Seq=4687 Ack=2264 Win=16863 Len=0 TLSv1.2 105 Change Cipher Spec, Encrypted Handshake Message TLSv1.2 153 Application Data TCP 60 443 → 44566 [ACK] Seq=4738 Ack=2363 Win=16962 Len=0 TLSv1.2 642 Application Data TLSv1.2 88 Application Data TCP 54 44566 → 443 [ACK] Seq=2363 Ack=5360 Win=261888 Len=0 TCP 54 44566 → 443 [RST, ACK] Seq=2363 Ack=5360 Win=0 Len=0
这段代码之前能正常运行,突然就失效了。Linux机器上用等效的cUrl请求可以正常工作,所以问题应该和.NET相关。我试过用RestSharp,但推测它底层还是用HttpClient,所以遇到同样的错误。我已经用nmap --script ssl-enum-ciphers扫描目标URL,并且修改HTTP Handler指定SSL协议和密码套件,但结果没有变化。
请问接下来应该怎么排查?
更新1:
已获取Linux系统的TCP抓包,发现RST是由于ssl handshake timeout exceeded导致。我认为无法通过HttpClient跳过SSL验证,只能忽略验证结果。尝试用SslStream,但这个组件也没有相关设置。
更新2:
已添加事件监听器并在控制台打印日志。同时在Linux虚拟机中运行代码,以便Wireshark捕获虚拟接口的全部流量(此前仅过滤目标IP)。
内容的提问来源于stack exchange,提问作者herme 0

