Pracuję nad projektem, który musi łączyć się z witryną https. Za każdym razem, gdy się łączę, mój kod generuje wyjątek, ponieważ certyfikat tej witryny pochodzi z niezaufanej witryny. Czy istnieje sposób na obejście sprawdzania certyfikatu w .net core http?
Widziałem ten kod z poprzedniej wersji .NET. Chyba po prostu potrzebuję czegoś takiego.
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
c#
ssl
asp.net-core
ssl-certificate
Ramppy Dumppy
źródło
źródło
Odpowiedzi:
Usługa ServicePointManager.ServerCertificateValidationCallback nie jest obsługiwana w .Net Core.
Obecna sytuacja jest taka, że będzie to nowa metoda ServerCertificateCustomValidationCallback dla przyszłego kontraktu 4.1. * System.Net.Http (HttpClient). Zespół .NET Core finalizuje teraz kontrakt 4.1. Możesz o tym przeczytać tutaj na githubie
Możesz wypróbować przedpremierową wersję System.Net.Http 4.1, korzystając ze źródeł bezpośrednio tutaj w CoreFx lub w kanale MYGET: https://dotnet.myget.org/gallery/dotnet-core
Bieżąca definicja WinHttpHandler.ServerCertificateCustomValidationCallback w serwisie Github
źródło
Aktualizacja:
Jak wspomniano poniżej, nie wszystkie implementacje obsługują to wywołanie zwrotne (np. Platformy takie jak iOS). W tym przypadku, jak mówią dokumenty , możesz jawnie ustawić walidator:
Działa to również w przypadku .NET Core 2.2, 3.0 i 3.1
Stara odpowiedź , z większą kontrolą, ale może rzucić
PlatformNotSupportedException
:Możesz zastąpić sprawdzanie certyfikatu SSL w wywołaniu HTTP za pomocą funkcji anonimowego wywołania zwrotnego, takiej jak ta
using (var httpClientHandler = new HttpClientHandler()) { httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; using (var client = new HttpClient(httpClientHandler)) { // Make your request... } }
Dodatkowo sugeruję użycie wzorca fabrycznego,
HttpClient
ponieważ jest to obiekt współdzielony, który może nie zostać natychmiast usunięty, a zatem połączenia pozostaną otwarte .źródło
HttpClient
właściwość o nazwie,DangerousAcceptAnyServerCertificateValidator
która umożliwia wykonanie tego zadania w systemie MacOSX. Więcej informacji tutaj - github.com/dotnet/corefx/pull/19908factory pattern
dlaHttpClient
?GetHttpClient
Metoda zwraca skonfigurowaneHttpClient
i użyj jej wusing
-blocku.Rozwiązuję tym:
Startup.cs
public void ConfigureServices(IServiceCollection services) { services.AddHttpClient("HttpClientWithSSLUntrusted").ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Manual, ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => { return true; } });
YourService.cs
public UserService(IHttpClientFactory clientFactory, IOptions<AppSettings> appSettings) { _appSettings = appSettings.Value; _clientFactory = clientFactory; } var request = new HttpRequestMessage(... var client = _clientFactory.CreateClient("HttpClientWithSSLUntrusted"); HttpResponseMessage response = await client.SendAsync(request);
źródło
Przyszedłem tutaj, szukając odpowiedzi na ten sam problem, ale używam WCF dla NET Core. Jeśli jesteś na tej samej łodzi, użyj:
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication() { CertificateValidationMode = X509CertificateValidationMode.None, RevocationMode = X509RevocationMode.NoCheck };
źródło
W .NetCore możesz dodać następujący fragment kodu w metodzie konfiguracji usług, dodałem sprawdzenie, aby upewnić się tylko, że przekazujemy certyfikat SSL tylko w środowisku programistycznym
services.AddHttpClient("HttpClientName", client => { // code to configure headers etc.. }).ConfigurePrimaryHttpMessageHandler(() => { var handler = new HttpClientHandler(); if (hostingEnvironment.IsDevelopment()) { handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; } return handler; });
źródło
Napotkałem ten sam problem podczas pracy z samopodpisanymi certyfikatami i uwierzytelnianiem certyfikatów klienta w kontenerach .NET Core 2.2 i Docker Linux. Wszystko działało dobrze na moim deweloperskim komputerze z Windowsem, ale w Dockerze dostałem taki błąd:
Na szczęście certyfikat został wygenerowany przy użyciu łańcucha. Oczywiście zawsze możesz zignorować to rozwiązanie i skorzystać z powyższych rozwiązań.
Oto moje rozwiązanie:
Certyfikat zapisałem za pomocą przeglądarki Chrome na moim komputerze w formacie P7B .
Konwertuj certyfikat do formatu PEM za pomocą tego polecenia:
openssl pkcs7 -inform DER -outform PEM -in <cert>.p7b -print_certs > ca_bundle.crt
Otwórz plik ca_bundle.crt i usuń wszystkie nagrania podmiotu, pozostawiając czysty plik. Przykład poniżej:
# Update system and install curl and ca-certificates RUN apt-get update && apt-get install -y curl && apt-get install -y ca-certificates # Copy your bundle file to the system trusted storage COPY ./ca_bundle.crt /usr/local/share/ca-certificates/ca_bundle.crt # During docker build, after this line you will get such output: 1 added, 0 removed; done. RUN update-ca-certificates
var address = new EndpointAddress("https://serviceUrl"); var binding = new BasicHttpsBinding { CloseTimeout = new TimeSpan(0, 1, 0), OpenTimeout = new TimeSpan(0, 1, 0), ReceiveTimeout = new TimeSpan(0, 1, 0), SendTimeout = new TimeSpan(0, 1, 0), MaxBufferPoolSize = 524288, MaxBufferSize = 65536, MaxReceivedMessageSize = 65536, TextEncoding = Encoding.UTF8, TransferMode = TransferMode.Buffered, UseDefaultWebProxy = true, AllowCookies = false, BypassProxyOnLocal = false, ReaderQuotas = XmlDictionaryReaderQuotas.Max, Security = { Mode = BasicHttpsSecurityMode.Transport, Transport = new HttpTransportSecurity { ClientCredentialType = HttpClientCredentialType.Certificate, ProxyCredentialType = HttpProxyCredentialType.None } } }; var client = new MyWSClient(binding, address); client.ClientCredentials.ClientCertificate.Certificate = GetClientCertificate("clientCert.pfx", "passwordForClientCert"); // Client certs must be installed client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication { CertificateValidationMode = X509CertificateValidationMode.ChainTrust, TrustedStoreLocation = StoreLocation.LocalMachine, RevocationMode = X509RevocationMode.NoCheck };
Metoda GetClientCertificate:
private static X509Certificate2 GetClientCertificate(string clientCertName, string password) { //Create X509Certificate2 object from .pfx file byte[] rawData = null; using (var f = new FileStream(Path.Combine(AppContext.BaseDirectory, clientCertName), FileMode.Open, FileAccess.Read)) { var size = (int)f.Length; var rawData = new byte[size]; f.Read(rawData, 0, size); f.Close(); } return new X509Certificate2(rawData, password); }
źródło
Po pierwsze, NIE UŻYWAJ GO W PRODUKCJI
Jeśli używasz oprogramowania pośredniczącego AddHttpClient, będzie to przydatne. Myślę, że jest to potrzebne w celu rozwoju, a nie produkcji. Dopóki nie utworzysz ważnego certyfikatu, możesz używać tej funkcji.
Func<HttpMessageHandler> configureHandler = () => { var bypassCertValidation = Configuration.GetValue<bool>("BypassRemoteCertificateValidation"); var handler = new HttpClientHandler(); //!DO NOT DO IT IN PRODUCTION!! GO AND CREATE VALID CERTIFICATE! if (bypassCertValidation) { handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, x509Certificate2, x509Chain, sslPolicyErrors) => { return true; }; } return handler; };
i zastosuj jak
services.AddHttpClient<IMyClient, MyClient>(x => { x.BaseAddress = new Uri("https://localhost:5005"); }) .ConfigurePrimaryHttpMessageHandler(configureHandler);
źródło
Zezwalanie na wszystkie certyfikaty jest bardzo potężne, ale może być również niebezpieczne. Jeśli chcesz zezwolić tylko na ważne certyfikaty oraz niektóre określone certyfikaty, możesz to zrobić w ten sposób.
using (var httpClientHandler = new HttpClientHandler()) { httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => { if (sslPolicyErrors == SslPolicyErrors.None) { return true; //Is valid } if (cert.GetCertHashString() == "99E92D8447AEF30483B1D7527812C9B7B3A915A7") { return true; } return false; }; using (var httpClient = new HttpClient(httpClientHandler)) { var httpResponse = httpClient.GetAsync("https://example.com").Result; } }
Pierwotnym źródłem:
https://stackoverflow.com/a/44140506/3850405
źródło