【问题标题】:c# Https call to self signed endpoint timeout (curl works)c# Https 调用自签名端点超时(curl 有效)
【发布时间】:2021-11-04 13:22:00
【问题描述】:

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

   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 的相同请求有效
  • 100s后超时,而httpClient.Timeout只有60s

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

【问题讨论】:

  • 我不确定您的目标是哪个 .net 核心版本。 github.com/dotnet/runtime/issues/30242
  • 我正在运行核心 3.1。我尝试添加一个 SocketsHttpHandler 作为我的 clientHandler 但这并没有解决问题。我可以尝试有关配置的任何想法吗?
  • HttpClient 默认超时时间为 100 秒。尝试 HttpClientFactory 可能会有所帮助。
  • 在我们的原始代码库(也存在问题)中,我们使用的是 HttpClientFactory,但为了简单起见,我将其省略了。
  • 尝试设置 'DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0' 在这里检查。 github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/…medium.com/@joni2nja/…

标签: c# .net-core dotnet-httpclient


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    相关资源
    最近更新 更多