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 相同的请求有效
- 100s后超时,而httpClient.Timeout只有60s
有人知道这里会发生什么吗?即使 Curl 成功,它仍然是防火墙问题吗?
原来是防火墙问题,但是很讨厌。
- 在我们的 CA 证书中定义了 pki.ourdomain.org。
- C# HTTP 库在请求期间的某个时刻调用了 URL(尽管 ServerCertificateCustomValidationCallback 返回 true)
- Curl 和 python(请求)不进行此调用,因此它们不会超时。
- 我们的防火墙丢弃了对该 pki 域的请求,没有任何错误或响应。
- 这导致 HTTP 请求最终超时,但没有任何相关错误消息。
当我们发现这个原因时,我们将 pki.* url 添加到防火墙规则中。
没有防火墙更改的更 hacky 解决方案是添加 pki.ourdomain.org 以定向到本地主机。这使得pki请求瞬间失败,原来的请求正常执行。
我仍然不完全理解为什么 C# 库有这种行为而其他客户端没有,但我希望这可以帮助别人。
我们正在 运行 在 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 相同的请求有效
- 100s后超时,而httpClient.Timeout只有60s
有人知道这里会发生什么吗?即使 Curl 成功,它仍然是防火墙问题吗?
原来是防火墙问题,但是很讨厌。
- 在我们的 CA 证书中定义了 pki.ourdomain.org。
- C# HTTP 库在请求期间的某个时刻调用了 URL(尽管 ServerCertificateCustomValidationCallback 返回 true)
- Curl 和 python(请求)不进行此调用,因此它们不会超时。
- 我们的防火墙丢弃了对该 pki 域的请求,没有任何错误或响应。
- 这导致 HTTP 请求最终超时,但没有任何相关错误消息。
当我们发现这个原因时,我们将 pki.* url 添加到防火墙规则中。 没有防火墙更改的更 hacky 解决方案是添加 pki.ourdomain.org 以定向到本地主机。这使得pki请求瞬间失败,原来的请求正常执行。
我仍然不完全理解为什么 C# 库有这种行为而其他客户端没有,但我希望这可以帮助别人。