web-dev-qa-db-de.com

HTTPS-Anforderung schlägt mit HttpClient fehl

Ich verwende den folgenden Code und erhalte die Ausnahme HttpRequestException:

using (var handler = new HttpClientHandler())
{
    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
    handler.SslProtocols = SslProtocols.Tls12;
    handler.ClientCertificates.Add(new X509Certificate2(@"C:\certificates\cert.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:\certificates\cert.crt"));
    //handler.ClientCertificates.Add(new X509Certificate2(@"C:\certificates\cert_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.
    }
}

Die Ausnahme:

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()

Ich habe auch versucht, die gleichen Zertifikate in den Windows Certificate Store zu exportieren und über Google zu verwenden Chrome und es funktioniert einwandfrei (der Browser hat mich gebeten, das installierte Zertifikat zu bestätigen und dann die Ressource zu laden).

Warum funktioniert es in meinem Code nicht?

[~ # ~] aktualisiert [~ # ~]

Ich habe auch versucht, einen Rückruf hinzuzufügen, um das Zertifikat zu validieren:

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

UPDATED2

Das Zertifikat wird SHA-1 verwendet. Neil Moss wird in den Kommentaren erwähnt, dass die Unterstützung für SHA1-Zertifikate wird zurückgezogen . Wenn es der wahre Grund ist, warum es nicht funktioniert, gibt es eine Problemumgehung dafür?

[~ # ~] Lösung [~ # ~]

Vielen Dank, Neil Moss, für die Lösung. Er schlug vor, das Tls-Flag für das SSL-Protokoll zu verwenden.

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

Es erforderte aber auch folgendes:

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

Nachdem ich dieses hinzugefügt habe, funktioniert es gut.

22
hcp

Gemäß this SO post müssen Sie TLS1.2 mit ServicePointManager aktivieren.

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

Bemerkenswert ist auch, dass die Eigenschaft MSDN-Dokumentation für ServicePointManager.SecurityProtocols die folgende Aussage trifft:

.NET Framework 4.6 enthält eine neue Sicherheitsfunktion, die unsichere Verschlüsselungs- und Hashing-Algorithmen für Verbindungen blockiert.

was darauf hindeutet, dass eine Form von SHA1-Block vorhanden sein könnte .

20
Neil Moss

Dies war ein sehr hilfreiches Dokument. Für ASP.NET Core 2.0 wurde die Antwort wie folgt angewendet (das Ergebnis war erfolgreich):

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;
        }
    }
}
3
Debro012