ChatGPT解决这个技术问题 Extra ChatGPT

bypass invalid SSL certificate in .net core

I am working on a project that needs to connect to an https site. Every time I connect, my code throws exception because the certificate of that site comes from untrusted site. Is there a way to bypass certificate check in .net core http?

I saw this code from previous version of .NET. I guess I just need something like this.

 ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
If anyone reading this Q&A is trying to ignore SSL verification for a client SignalR hub connection, see here - stackoverflow.com/a/59835125/1549918.

k
kdaveid

Update:

As mentioned below, not all implementations support this callback (i.e. platforms like iOS). In this case, as the docs say, you can set the validator explicitly:

handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

This works too for .NET Core 2.2, 3.0 and 3.1

Old answer, with more control but may throw PlatformNotSupportedException:

You can override SSL cert check on a HTTP call with the a anonymous callback function like this

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

Additionally, I suggest to use a factory pattern for HttpClient because it is a shared object that might no be disposed immediately and therefore connections will stay open.


I am using .Net Core 1.0 and this worked for me. As a heads up it looks like .Net Core 2.0 has added an HttpClient property called DangerousAcceptAnyServerCertificateValidator which provides a way to make this work on MacOSX. More info here - github.com/dotnet/corefx/pull/19908
Using this with AWS Lambda, .NET Core 1.0 corrected what was preventing me from connecting to an internal HTTPS with a custom root CA cert.
Any factory pattern for HttpClient ?
@Kiquenet Just create a factory, where the GetHttpClient Method returns the configured HttpClient and use it within a using-block.
This should be the accepted answer, especially since it can be scoped to a single client use.
O
O.Machado

I solve with this:

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

you are a life saver!
T
Troels Larsen

Came here looking for an answer to the same problem, but I'm using WCF for NET Core. If you're in the same boat, use:

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

Global for all certificates and AppDomain ?
@Kiquenet: I believe so, yes. Check for an updated answer elsewhere, there might be a better solution now. It's been a year. I guess you could subclass the authenticator if nothing else. And no, there is no native factory for HttpClient that I know off. If you need more functionality, look at RestClient.
There is no ClientCredentials property in HttpClient (.NET Core 3.1).
@Павле: I haven't updated this project to 3.1 yet, but there should be such a property: docs.microsoft.com/en-us/dotnet/api/….
@Павле: This answer is not about HttpClient but a WCF Service generated client. Worked for my ASMX SoapClient too, many thanks!
S
Set

ServicePointManager.ServerCertificateValidationCallback isn't supported in .Net Core.

Current situation is that it will be a a new ServerCertificateCustomValidationCallback method for the upcoming 4.1.* System.Net.Http contract (HttpClient). .NET Core team are finalizing the 4.1 contract now. You can read about this in here on github

You can try out the pre-release version of System.Net.Http 4.1 by using the sources directly here in CoreFx or on the MYGET feed: https://dotnet.myget.org/gallery/dotnet-core

Current WinHttpHandler.ServerCertificateCustomValidationCallback definition on Github


This only works on Windows. Do you have a solution for Linux? Thanks.
S
Sameh

In .NetCore, you can add the following code snippet at services configure method , I added a check to make sure only that we by pass the SSL certificate in development environment only

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

Why the -ve, this is exactly implementing what others suggested in mvc.net code and they scored points on it , i am just illustrating the same implementation in .netCore code
probably. because it lacks any explanation whatsoever. why this approach should be take over any other, What code should be written in calling section (say mycontroller.cs), which could be part of explanation. any official documentation/citation.
As I said if you reviewed other comments at the top of the thread there is no much difference and yet they scored 18 and 81 points ,
because they have added text supporting their answers, please read the guidelines once more. Might help you, @moderators can point to the exact problems IMHO.
If in .net core you use an unnamed httpclient, just put "" instead of "HttpClientName".
G
Giulio Caccin

I faced off the same problem when working with self-signed certs and client cert auth on .NET Core 2.2 and Docker Linux containers. Everything worked fine on my dev Windows machine, but in Docker I got such error:

System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure

Fortunately, the certificate was generated using a chain. Of course, you can always ignore this solution and use the above solutions.

So here is my solution:

I saved the certificate using Chrome on my computer in P7B format. Convert certificate to PEM format using this command: openssl pkcs7 -inform DER -outform PEM -in .p7b -print_certs > ca_bundle.crt Open the ca_bundle.crt file and delete all Subject recordings, leaving a clean file. Example below:

    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----

Put these lines to the Dockerfile (in the final steps):

    # 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

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

GetClientCertificate method:

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

O
Ogglas

Allowing all certificates is very powerful but it could also be dangerous. If you would like to only allow valid certificates plus some certain certificates it could be done like this.

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

Original source:

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


O
Ozan ERTÜRK

Firstly, DO NOT USE IT IN PRODUCTION

If you are using AddHttpClient middleware this will be usefull. I think it is needed for development purpose not production. Until you create a valid certificate you could use this 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;
        };

and apply it like

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

S
Ssh Quack

For .NET 6 you can configure your primary Http message handler like this:

services.AddHttpClient<ITodoListService, TodoListService>()
    .ConfigurePrimaryHttpMessageHandler(() => {
        var handler = new HttpClientHandler();

        if (currentEnvironment.IsDevelopment()) {
            handler.ServerCertificateCustomValidationCallback =
                HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
        }

        return handler;
    });

Link to official docs