2017-03-12 66 views
11

Używam poniższy kod i uzyskać HttpRequestException wyjątek:żądanie HTTPS nie używając HttpClient

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. 
    } 
} 

Wyjątek:

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

Próbowałem też na eksport tych samych certyfikatów Windows Store i stosowania certyfikatów to przez Google Chrome i działa dobrze (przeglądarka poprosiła mnie o potwierdzenie zainstalowanego certyfikatu, a następnie załadował zasób).

Dlaczego to nie działa w moim kodzie?

AKTUALIZACJA

Próbowałem też dodać oddzwanianie do sprawdzania poprawności certyfikatu:

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

UPDATED2

Świadectwo służy SHA-1. Neil Moss jest wymieniony w komentarzach: support for SHA1 certs is being withdrawn. Jeśli to jest prawdziwy powód, dla którego to nie działa, czy istnieje obejście tego problemu?

ROZWIĄZANIE

Dziękuję Neil Moss do rozwiązania. Zaproponował użycie flagi Tls dla protokołu SSL.

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

Ale to również wymagane są następujące:

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

Po dodałem ten jeden działa dobrze.

+2

Proszę podać pełne informacje o błędzie: typ, komunikat i ślad stosu. Jeśli istnieje wyjątek wewnętrzny, co to jest? – Richard

+0

Witam @Richard, zaktualizowałem moje pytanie z komunikatami wyjątku i trakcjami stosu. – hcp

+0

Żeby było jasne, czy próbujesz połączyć się przez HTTPS za pomocą _klienta certyfikatu_, czy próbujesz dołączyć samopodpisany certyfikat _serwera_, który chcesz traktować jako prawidłowy? –

Odpowiedz

12

Zgodnie z this SO post, musisz włączyć TLS1.2 z ServicePointManager.

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

również zauważyć, MSDN documentation nieruchomości ServicePointManager.SecurityProtocols sprawia, że ​​to oświadczenie:

The .NET Framework 4.6 includes a new security feature that blocks insecure cipher and hashing algorithms for connections.

co sugeruje, że jakaś forma bloku SHA1 może być na swoim miejscu.

+1

Dziękuję bardzo, Neil Moss! Po dodaniu protokołu Tls działa! Ale jak wiem, nie ma "System.Net.ServicePointManager.SecurityProtocol", ale użyłem 'handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; ' – hcp

+0

Ważne, aby pamiętać, że .net core 2.0, będziesz musiał użyć HttpClientHandler zamiast ServicePointManager. –