Сбой запроса HTTPS с использованием HttpClient

Я использую следующий код и вам HttpRequestException исключения:

using (var handler = new HttpClientHandler())
{
    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
    handler.SslProtocols = SslProtocols.Tls12;
    handler.ClientCertificates.Add(new X509Certificate2(@"C:certificatescert.pfx"));

    // I also tried to add another certificates that was provided to https access 
    // by administrators of the site, but it still doesn't work.
    //handler.ClientCertificates.Add(new X509Certificate2(@"C:certificatescert.crt"));
    //handler.ClientCertificates.Add(new X509Certificate2(@"C:certificatescert_ca.crt"));

    using (var client = new HttpClient(handler))
    {
        var response = client.GetAsync("https://someurl.com/api.php?arg1=some&arg2=test").GetAwaiter().GetResult();
        // ^ HttpRequestException: An error occurred while sending the request.
    }
}

исключение:

WinHttpException: A security error occurred
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
    System.Net.Http.WinHttpHandler+<StartRequest>d__105.MoveNext()

HttpRequestException: An error occurred while sending the request.
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult()
    System.Net.Http.HttpClient+<FinishSendAsync>d__58.MoveNext()
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    MyApp.Web.Controllers.HomeController.Test() in HomeController.cs
        var response = client.GetAsync("https://someurl.com/api.php?arg1=some&arg2=test").GetAwaiter().GetResult();
    lambda_method(Closure , object , Object[] )
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeActionMethodAsync>d__27.MoveNext()

Я также попытался экспортировать те же сертификаты в хранилище сертификатов Windows и использовать его через Google Chrome ,и он отлично работает (браузер попросил меня подтвердить установленный сертификат, а затем загрузил ресурс).

почему это не работает в моем коде?

обновлено

Я также попытался добавить обратный вызов для проверки сертификат:

handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) =>
{
    // I set a breakpoint to this point but it is not catched.
    return true;
};

UPDATED2

сертификат используется SHA-1. Нил Мосс упоминается в комментариях, что поддержка сертификатов SHA1 отзывается. Если это реальная причина, почему он не работает, есть ли обходной путь для этого?

решение

спасибо Нил Мосс за решение. Он предложил использовать флаг Tls для протокола SSL.

handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;

но он также требовал следующий:

handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;

после того, как я добавил это работает отлично.

2 ответов


по данным это так пост, вы должны включить TLS1.2 с ServicePointManager.

System.Net.ServicePointManager.SecurityProtocol =
    SecurityProtocolType.Tls12 | 
    SecurityProtocolType.Tls11 | 
    SecurityProtocolType.Tls; // comparable to modern browsers

также примечательно, что документация MSDN для ServicePointManager.Свойство SecurityProtocols делает следующее утверждение:

.NET Framework 4.6 включает новую функцию безопасности, которая блокирует небезопасные алгоритмы шифрования и хэширования для соединений.

что предполагает, что некоторая форма блока SHA1 может быть на месте.


Это был очень полезный документ. Для ASP.NET Core 2.0, ответ был применен следующим образом (результат был успешным):

using (var handler = new HttpClientHandler())
{
    handler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
    handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
    using (HttpClient client = new HttpClient(handler))
    {
        string requestObjJson = requestObj.ToJson();
        var address = new Uri($"https://yourcompany.com/");
        string token = GetToken();
        client.BaseAddress = address;
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        var contentData = new StringContent(requestObjJson, System.Text.Encoding.UTF8, "application/json");
        using (var response = await client.PostAsync("yourcompany/new-employee", contentData))
        {
            var content = response.Content.ReadAsStringAsync();
            var taskResult = content.Result;
            JObject resultObj = JObject.Parse(taskResult);
            return resultObj;
        }
    }
}