ignora il certificato SSL non valido in .net core


104

Sto lavorando a un progetto che deve connettersi a un sito https. Ogni volta che mi connetto, il mio codice genera un'eccezione perché il certificato di quel sito proviene da un sito non attendibile. C'è un modo per aggirare il controllo dei certificati in .net core http?

Ho visto questo codice dalla versione precedente di .NET. Credo di aver solo bisogno di qualcosa del genere.

 ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

Risposte:


28

ServicePointManager.ServerCertificateValidationCallback non è supportato in .Net Core.

La situazione attuale è che sarà un nuovo metodo ServerCertificateCustomValidationCallback per il prossimo contratto 4.1. * System.Net.Http (HttpClient). Il team .NET Core sta finalizzando il contratto 4.1 ora. Puoi leggere questo argomento qui su GitHub

Puoi provare la versione pre-rilascio di System.Net.Http 4.1 utilizzando i sorgenti direttamente qui in CoreFx o sul feed MYGET: https://dotnet.myget.org/gallery/dotnet-core

Definizione WinHttpHandler.ServerCertificateCustomValidationCallback corrente su Github


8
Funziona solo su Windows. Hai una soluzione per Linux? Grazie.
Vladimir

146

Aggiornare:

Come accennato di seguito, non tutte le implementazioni supportano questa richiamata (ovvero piattaforme come iOS). In questo caso, come dicono i documenti , puoi impostare esplicitamente il validatore:

handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

Funziona anche per .NET Core 2.2, 3.0 e 3.1

Vecchia risposta , con più controllo ma può lanciare PlatformNotSupportedException:

Puoi sovrascrivere il controllo del certificato SSL su una chiamata HTTP con la funzione di richiamata anonima come questa

using (var httpClientHandler = new HttpClientHandler())
{
   httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
   using (var client = new HttpClient(httpClientHandler))
   {
       // Make your request...
   }
}

Inoltre, suggerisco di utilizzare un pattern factory per HttpClientperché è un oggetto condiviso che potrebbe non essere eliminato immediatamente e quindi le connessioni rimarranno aperte .


3
Sto usando .Net Core 1.0 e questo ha funzionato per me. A proposito , sembra che .Net Core 2.0 abbia aggiunto una HttpClientproprietà chiamata DangerousAcceptAnyServerCertificateValidatorche fornisce un modo per farlo funzionare su MacOSX. Maggiori informazioni qui - github.com/dotnet/corefx/pull/19908
Troy Witthoeft

1
Usando questo con AWS Lambda, .NET Core 1.0 ha corretto ciò che mi impediva di connettermi a un HTTPS interno con un certificato CA radice personalizzato.
QuickNull

Qualcuno factory patternper HttpClient?
Kiquenet

@Kiquenet Basta creare una fabbrica, dove il GetHttpClientMetodo restituisce il configurato HttpCliente lo usa all'interno di un usingblocco.
LuckyLikey

Questa dovrebbe essere la risposta accettata, soprattutto perché può essere limitata a un singolo utilizzo del client.
BinaryPatrick

37

Risolvo con questo:

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

32

Sono venuto qui alla ricerca di una risposta allo stesso problema, ma sto usando WCF per NET Core. Se sei sulla stessa barca, usa:

client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = 
    new X509ServiceCertificateAuthentication()
    {
        CertificateValidationMode = X509CertificateValidationMode.None,
        RevocationMode = X509RevocationMode.NoCheck
    };

Globale per tutti i certificati e AppDomain?
Kiquenet

@Kiquenet: credo di sì, sì. Cerca una risposta aggiornata altrove, potrebbe esserci una soluzione migliore ora. È passato un anno. Immagino che potresti sottoclassare l'autenticatore se non altro. E no, non esiste una factory nativa per HttpClient che conosco. Se hai bisogno di più funzionalità, guarda RestClient.
Troels Larsen

Non esiste alcuna proprietà ClientCredentials in HttpClient (.NET Core 3.1).
Павле

@ Павле: Non ho ancora aggiornato questo progetto alla 3.1, ma dovrebbe esserci una tale proprietà: docs.microsoft.com/en-us/dotnet/api/… .
Troels Larsen,

@ Павле: questa risposta non riguarda HttpClient ma un client generato dal servizio WCF. Ha funzionato anche per il mio ASMX SoapClient, molte grazie!
Jan Zahradník

14

In .NetCore, è possibile aggiungere il seguente frammento di codice al metodo di configurazione dei servizi, ho aggiunto un controllo per assicurarmi solo che il certificato SSL venga superato solo nell'ambiente di sviluppo

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;
              });

1
Perché -ve, questo sta implementando esattamente ciò che altri hanno suggerito nel codice mvc.net e hanno ottenuto punti su di esso, sto solo illustrando la stessa implementazione nel codice .netCore
Sameh

probabilmente. perché manca di qualsiasi spiegazione. perché questo approccio dovrebbe essere sostituito da qualsiasi altro, Quale codice dovrebbe essere scritto nella sezione di chiamata (ad esempio mycontroller.cs), che potrebbe essere parte della spiegazione. qualsiasi documentazione / citazione ufficiale.
Bhanu Chhabra

Come ho detto, se hai rivisto altri commenti all'inizio del thread non c'è molta differenza eppure hanno segnato 18 e 81 punti,
Sameh

1
poiché hanno aggiunto del testo a sostegno delle loro risposte, leggi ancora una volta le linee guida. Potrebbe aiutarti, @moderators può indicare i problemi esatti IMHO.
Bhanu Chhabra

8

Ho affrontato lo stesso problema lavorando con certificati autofirmati e autenticazione certificato client su .NET Core 2.2 e Docker Linux. Tutto ha funzionato bene sulla mia macchina Windows di sviluppo, ma in Docker ho ricevuto questo errore:

System.Security.Authentication.AuthenticationException: il certificato remoto non è valido in base alla procedura di convalida

Fortunatamente, il certificato è stato generato utilizzando una catena. Naturalmente, puoi sempre ignorare questa soluzione e utilizzare le soluzioni di cui sopra.

Quindi ecco la mia soluzione:

  1. Ho salvato il certificato utilizzando Chrome sul mio computer in formato P7B .

  2. Converti certificato in formato PEM utilizzando questo comando:
    openssl pkcs7 -inform DER -outform PEM -in <cert>.p7b -print_certs > ca_bundle.crt

  3. Apri il file ca_bundle.crt ed elimina tutte le registrazioni del Soggetto, lasciando un file pulito. Esempio sotto:

    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
  1. Metti queste righe nel Dockerfile (nei passaggi finali):
    # 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
  1. Nell'app:
    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
    };

Metodo 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);
}

4

In primo luogo, NON USARLO IN PRODUZIONE

Se stai usando il middleware AddHttpClient, questo sarà utile. Penso che sia necessario per lo sviluppo e non per la produzione. Fino a quando non crei un certificato valido puoi usare questo Func.

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

e applicalo come

services.AddHttpClient<IMyClient, MyClient>(x => { x.BaseAddress = new Uri("https://localhost:5005"); })
        .ConfigurePrimaryHttpMessageHandler(configureHandler);

3

Consentire tutti i certificati è molto potente ma potrebbe anche essere pericoloso. Se desideri consentire solo certificati validi più alcuni determinati certificati, potresti farlo in questo modo.

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

Fonte originale:

https://stackoverflow.com/a/44140506/3850405

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.