c# HTTPS 调用自签名端点超时(curl 有效)

c# Https call to self signed endpoint timeout (curl works)

我们正在 运行 在 ubuntu 18.04 上安装 C# 应用程序 (.net Core 3.1)。 应用程序向自签名 https 端点发出 http 请求,但该请求被取消。我设法使用以下代码片段重现了它:

   class Program {
    static async Task Main(string[] args)
    {
        const string url = "https://my-endpoint.com/path/";
        const string basicAuth = "user:password";
        
        var httpClientHandler = new HttpClientHandler();
        httpClientHandler.ServerCertificateCustomValidationCallback =
            (message, cert, chain, sslPolicyErrors) => true;

        HttpClient httpClient = new HttpClient(httpClientHandler);            
        var authHeader = new AuthenticationHeaderValue("Basic",
            Convert.ToBase64String(Encoding.UTF8.GetBytes(basicAuth)));
        httpClient.DefaultRequestHeaders.Authorization = authHeader;
        httpClient.Timeout = TimeSpan.FromSeconds(60);

        Stopwatch watch = null;
        try
        {
            watch = Stopwatch.StartNew();
            var result = await httpClient.GetAsync(url);
            watch.Stop();
            Console.WriteLine($"Took {watch.ElapsedMilliseconds} milliseconds");
            Console.WriteLine(await result.Content.ReadAsStringAsync());
        }
        catch (Exception e)
        {
            watch?.Stop();
            Console.WriteLine($"Took {watch?.ElapsedMilliseconds} milliseconds");
            throw;
        }
        
    }
}

当我 运行 在本地执行此操作时它会成功,但在 linux 服务器上它会生成以下输出:

Took 100239 milliseconds
Unhandled exception. System.Threading.Tasks.TaskCanceledException: The operation was canceled.
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at HTTPTest.Program.Main(String[] args) in C:\Users\nlfsmi\src\iotedge.kafkahttpbridgemodule\HTTPTest\Program.cs:line 31
   at HTTPTest.Program.<Main>(String[] args)
Aborted

我注意到的奇怪事情:

有人知道这里会发生什么吗?即使 Curl 成功,它仍然是防火墙问题吗?

原来是防火墙问题,但是很讨厌。

  • 在我们的 CA 证书中定义了 pki.ourdomain.org。
  • C# HTTP 库在请求期间的某个时刻调用了 URL(尽管 ServerCertificateCustomValidationCallback 返回 true)
  • Curl 和 python(请求)不进行此调用,因此它们不会超时。
  • 我们的防火墙丢弃了对该 pki 域的请求,没有任何错误或响应。
  • 这导致 HTTP 请求最终超时,但没有任何相关错误消息。

当我们发现这个原因时,我们将 pki.* url 添加到防火墙规则中。 没有防火墙更改的更 hacky 解决方案是添加 pki.ourdomain.org 以定向到本地主机。这使得pki请求瞬间失败,原来的请求正常执行。

我仍然不完全理解为什么 C# 库有这种行为而其他客户端没有,但我希望这可以帮助别人。