2017-03-10 62 views
9

Piszę aplikację .NET Core, aby sondować serwer zdalny i przesyłać dane w takiej postaci, w jakiej się pojawiają. Działa to doskonale w PHP, ponieważ PHP ignoruje certyfikat (co jest również problemem w przeglądarkach), ale chcemy przenieść to do C# .NET CORE, ponieważ jest to jedyny pozostały PHP w systemie.Zignoruj ​​zły certyfikat - .NET CORE

Wiemy, że serwer jest dobry, ale z różnych powodów certyfikat nie może/nie będzie aktualizowany w najbliższym czasie.

Żądanie używa HttpClient:

 HttpClient httpClient = new HttpClient(); 
     try 
     { 
      string url = "https://URLGoesHere.php"; 
      MyData md = new MyData(); // this is some data we need to pass as a json 
      string postBody = JsonConvert.SerializeObject(md); 
      httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));     
      HttpResponseMessage wcfResponse = await httpClient.PostAsync(url, new StringContent(postBody, Encoding.UTF8, "application/json")); 
      Console.WriteLine(wcfResponse.Content); 
     } 
     catch (HttpRequestException hre) 
     { 
     // This exception is being triggered 
     } 

Po zbadane to wydaje się, że zalecenie jest uniwersalny w użyciu ServicePointManager, ale to nie jest dostępne w .NET Rdzenia i mam problem ze znalezieniem zalecanej wymiany.

Czy jest prosty lub lepszy sposób to zrobić w .NET Core?

+2

może to być pomocne http://stackoverflow.com/questions/2675133/c-sharp-ignore-certificate-errors –

+2

Prawdopodobny duplikat [pomija nieprawidłowy certyfikat SSL w rdzeniu .net] (http://stackoverflow.com/questions/38138952/bypass-invalid-ssl-certificate-in-net-core) – thmshd

+2

Dzięki za wszystkie podpowiedzi do innych wątków - ale po odwiedzeniu ich wszystkich w przeszłości nadal mam problem - żaden z nich się nie skompiluje. Za każdym razem jest jakieś odniesienie, którego nie można znaleźć. Najwyraźniej brakuje tu czegoś oczywistego! Małe fragmenty nie dostarczają wystarczającej ilości informacji (jak dla mnie), jak to, co jeszcze należy uwzględnić lub z którym się odwołać. Ctrl-. nie przedstawia też żadnych rozsądnych sugestii. – DaveEP

Odpowiedz

5

Zamiast new HttpClient() chcesz coś podobnego do

var handler = new System.Net.Http.HttpClientHandler(); 
using (var httpClient = new System.Net.Http.HttpClient(handler)) 
{ 
    handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => 
    { 
     // Log it, then use the same answer it would have had if we didn't make a callback. 
     Console.WriteLine(cert); 
     return errors == SslPolicyErrors.None; 
    }; 

    ... 
} 

który powinien działać na Windows i Linux, gdzie libcurl jest skompilowany w użyciu OpenSSL. W przypadku innych zwrotnych linuksów Linux rzuci wyjątek.

+2

FYI, to nie działa w .NET Core 1.1 na Mac OS albo. Komunikat o wyjątku to: 'Używana biblioteka libcurl (7.51.0) i jej protokół SSL (" SecureTransport ") nie obsługują niestandardowej obsługi certyfikatów. Wymagana jest libcurl zbudowana za pomocą OpenSSL.) ' – Ricky

+0

Ricky, zobacz moją powyższą odpowiedź dla kilku opcji. –

+0

@bartonjs: Dziękuję za skierowanie mnie we właściwym kierunku, aby dowiedzieć się, jak to działa we wszystkich scenariuszach na makrach i prawdopodobnie w niektórych wersjach Linuksa. To było bardzo pomocne. –

2

Pierwsze Linux i MacOS pracować

Jeśli pracujesz w systemie Linux lub MacOS was mogą napotkać scenariusz, w którym HttpClient nie pozwoli Ci uzyskać dostęp do własnej podpisał cert nawet jeśli jest w zaufanym sklepie . otrzymasz prawdopodobnie następujący:

System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable 

od jeśli wykonawczych (jak pokazano w drugiej odpowiedzi)

handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => 
{ 
    // Log it, then use the same answer it would have had if we didn't make a callback. 
    Console.WriteLine(cert); 
    return errors == SslPolicyErrors.None; 
}; 

Wynika to z wersji libcurl na maszynie nie wspierającego odpowiednie wywołania zwrotne że .Net Core musi w celu zebrania odpowiednich danych, aby zadzwonić na numer ServerCertificateCustomValidationCallback. Na przykład, nie ma sposobu, aby struktura stworzyła obiekt cert lub inny z parametrów. Więcej informacji można znaleźć w dyskusji na obejście tego problemu, który został przewidziany w .NET Rdzenia sporne w DotNet rdzenia github repo:

https://github.com/dotnet/corefx/issues/19709

Obejście (które powinny być wykorzystywane jedynie do testowania lub konkretnych zastosowań wewnętrznych) jest następujący:

using System; 
using System.Net.Http; 
using System.Runtime.InteropServices; 

namespace netcurl 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var url = "https://localhost:5001/.well-known/openid-configuration"; 
      var handler = new HttpClientHandler(); 
      using (var httpClient = new HttpClient(handler)) 
      { 
       // Only do this for testing and potentially on linux/mac machines 
       if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && IsTestUrl(url)) 
       { 
        handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; 
       } 

       var output = httpClient.GetStringAsync(url).Result; 

       Console.WriteLine(output); 
      } 
     } 

     static bool IsTestUrl(string url) => url.Contains("localhost"); 
    } 
} 

jest inna droga do rozwiązywania tego problemu, i że stosuje wersję libcurl, która jest skompilowany z obsługą openSSL.Dla MacOS, tutaj jest dobry tutorial jak zrobić to:

https://spin.atomicobject.com/2017/09/28/net-core-osx-libcurl-openssl/

dla krótkiej wersji, chwyć kopię najnowszej libcurl skompilowane ze wsparciem openssl:

brew install curl --with-openssl 

Prawdopodobnie don nie chcesz zmusić całego systemu operacyjnego do używania wersji libcurl innej niż Apple, więc będziesz prawdopodobnie chciał użyć zmiennej środowiskowej DYLD_LIBRARY_PATH zamiast używać brew, aby wymusić połączenie binariów z normalną ścieżką systemu operacyjnego.

export DYLD_LIBRARY_PATH=/usr/local/opt/curl/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH} 

Powyższe polecenie może być użyte do ustawienia odpowiedniej zmiennej środowiskowej po uruchomieniu dotnet w terminalu. Nie dotyczy to jednak aplikacji GUI. Jeśli używasz Visual Studio for Mac, można ustawić zmienną środowiskową w ustawieniach projektu uruchomić:

Visual Studio for Mac project run settings

Drugie podejście było konieczne dla mnie podczas korzystania IdentityServer4 i Token zezwolenia. Potok autoryzacji .NET Core 2.0 nawiązywał połączenie z urzędem tokenu przy użyciu instancji HttpClient. Ponieważ nie miałem dostępu do obiektu HttpClient lub jego obiektu HttpClientHandler, musiałem wymusić instancję HttpClient, aby użyć odpowiedniej wersji biblioteki libcurl, która zajmie moje korzenie systemu KeyChain dla mojego zaufanego certyfikatu. W przeciwnym razie uzyskałbym System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates environment variable podczas próby zabezpieczenia punktu końcowego Webapi przy użyciu atrybutu Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)].

Poświęciłem godziny na badanie tego przed znalezieniem pracy dookoła. Cały mój cel polegał na używaniu certyfikatu samopodpisanego podczas programowania dla macO za pomocą IdentityServer4 w celu zabezpieczenia mojego webapi. Mam nadzieję że to pomoże.

+0

Wielkie dzięki za twój post. Pomogło mi to we właściwym kierunku. Używamy .NET Standard 2.0 więc po pierwsze nie mogłem zrozumieć, dlaczego miałem do czynienia z tymi wszystkimi problemami ... Próbowałem WSZYSTKO z curl i openssl i tym rzeczy, nic mi nie pomogło. Poszedłem więc z paskudnym hackerem (nie mogłem sprawić, żeby twój przykładowy kod nie działał). 'if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) { handler.ServerCertificateCustomValidationCallback = null; } ' – martinmose