Use Httpclient to trust self-signed certificates


wood more wood

I'm trying to make a web request that fails due to a self-signed certificate:

Client = new HttpClient(); 
HttpResponseMessage Response = await Client.GetAsync(Uri)//defined elsewhere 

This will throw a trust failure exception.

I tried allowing untrusted SSL certificates again using HttpClient httpclienthandleras suggested here :

 var handler = new HttpClientHandler();

 handler.ServerCertificateCustomValidationCallback = 
 (
   HttpRequestMessage message, 
   X509Certificate2 cert, 
   X509Chain chain, 
   SslPolicyErrors errors
  ) =>{return true; };//remove if this makes it to production 

  Client = new HttpClient(handler); 

This throws an exception not implemented by the system.

Is there any other way to trust a self-signed certificate? I even installed the certificate on the machine making the request, but no luck.

Sushi Hangover

I've seen a lot of questions about this and thought I'd write an answer and example as complete as possible.

Note: See this answer when working with WKWebViewself-signed certificates

HttpClient implementation

Note: badssl.com is used in this example

managed (default)

System.Net.Http.HttpRequestException: Error sending request ---> System.Net.WebException: Error: TrustFailure(One or more errors occurred.) ---> System.AggregateException: One or more errors occurred . ---> System.Security.Authentication.AuthenticationException: The call to SSPI failed, see inner exception. ---> Mono.Security.Interface.Tl

From a security and performance standpoint, the original Mono Managedprovider has gone into real long -term and only supports TLS1.0, I'm going to move to using the NSUrlSession implementation.

CFNetwork(iOS 6+)

NOTE: Since this iOS version is pretty old now, I personally don't target it anymore, so I leave it blank... (unless someone really needs me to look up notes for it ;-)

NSUrlSession(iOS 7+)

Xamarin provides a subclass HttpMessageHandlerbased on iOS' ( NSUrlSessionHandler) NSUrlSession.

Using it alone for self-signed certificates results in:

System.Net.WebException: An SSL error occurred and a secure connection to the server could not be established. ---> Foundation.NSErrorException: An exception of type 'Foundation.NSErrorException' was thrown.

The problem is that self-signed certificates are considered insecure and not trusted by iOS, so you must apply an ATS exception to your app so that iOS knows your app is not trusted Info.plist.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>self-signed.badssl.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

Now that iOS knows your app is making an untrusted call, a request will HttpClientnow result in this error:

System.Net.WebException: The server's certificate is invalid. You may be connecting to a server pretending to be self-signed.badssl.com, which could put your confidential information at risk. ---> Foundation.NSErrorException: An exception of type 'Foundation.NSErrorException' was thrown.

This error is due to the fact that even if the ATS exception is allowed , the default settings provided by iOS NSUrlSessionwill apply its criteria NSUrlAuthenticationChallengeto the certificate and will fail because a self-signed certificate can never be truly authenticated (even with client pinning ) because it doesn't include an iOS-trusted root certificate authority (CA) in its chain.

So you need to intercept and bypass the certificate security checks provided by iOS (yes, big security alerts, flashing red lights, etc.)

However , you can do this by creating a subclass that NSUrlSessionDataDelegatebypasses .

public class SelfSignedSessionDataDelegate : NSUrlSessionDataDelegate, INSUrlSessionDelegate
{
    const string host = "self-signed.badssl.com";
    public override void DidReceiveChallenge(NSUrlSession session, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
    {
        switch (challenge.ProtectionSpace.Host)
        {
            case host:
                using (var cred = NSUrlCredential.FromTrust(challenge.ProtectionSpace.ServerSecTrust))
                {
                    completionHandler.Invoke(NSUrlSessionAuthChallengeDisposition.UseCredential, cred);
                }
                break;
            default:
                completionHandler.Invoke(NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, null);
                break;
        }
    }
}

Now you need to apply it to NSUrlSessionDataDelegate, NSUrlSessionand use that new session in the creation, which NSUrlSessionHandlerwill be provided in the constructor of HttpClient.

var url = "https://self-signed.badssl.com";
using (var selfSignedDelegate = new SelfSignedSessionDataDelegate())
using (var session = NSUrlSession.FromConfiguration(NSUrlSession.SharedSession.Configuration, (INSUrlSessionDelegate)selfSignedDelegate, NSOperationQueue.MainQueue))
using (var handler = new NSUrlSessionHandler(session))
using (var httpClient = new HttpClient(handler))
using (var response = await httpClient.GetAsync(url))
using (var content = response.Content)
{
    var result = await content.ReadAsStringAsync();
    Console.WriteLine(result);
}

Note: Just as an example, typically you would create a Delegate, NSUrlSession, HttpClient, NSUrlSessionHandler and reuse it for all requests (ie. Singleton pattern)

Your request is now valid:

<html>
   <head>
    <title>self-signed.badssl.com</title>
  </head>
  <body><div id="content"><h1 style="font-size: 12vw;">
    self-signed.<br>badssl.com
    </h1></div>
  </body>
</html>

Notice:NSUrlSessionProviding your own customization options to Xamarin NSUrlSessionHandleris brand new (November 2017) and is not currently in a release version (alpha, beta or stable), but of course sources are available from:

Use NSUrlSessioninstead HttpClient:

You can also use a directly NSUrlSessioninstead HttpClientof a certificate for a self-signed certificate.

var url = "https://self-signed.badssl.com";
using (var selfSignedDelegate = new SelfSignedSessionDataDelegate())
using (var session = NSUrlSession.FromConfiguration(NSUrlSession.SharedSession.Configuration, (INSUrlSessionDelegate)selfSignedDelegate, NSOperationQueue.MainQueue))
{
    var request = await session.CreateDataTaskAsync(new NSUrl(url));
    var cSharpString = NSString.FromData(request.Data, NSStringEncoding.UTF8).ToString(); 
    Console.WriteLine(cSharpString);
}

Note: Just as an example, typically you would create a Delegate and NSUrlSession and reuse it for all requests, i.e. Singleton pattern

real solution? Use a free security certificate:

IHMO, even in a development environment, avoid using self-signed certificates all together and use one of the free certificate services and avoid all the hassle of applying ATS exceptions, custom code to intercept/bypass iOS security, and make your Application web services are actually safe.

I personally use Let's Encrypt:

Related


Use Httpclient to trust self-signed certificates

wood more wood I'm trying to make a web request that fails due to a self-signed certificate: Client = new HttpClient(); HttpResponseMessage Response = await Client.GetAsync(Uri)//defined elsewhere This will throw a trust failure exception. I tried allowing

Use Httpclient to trust self-signed certificates

wood more wood I'm trying to make a web request that fails due to a self-signed certificate: Client = new HttpClient(); HttpResponseMessage Response = await Client.GetAsync(Uri)//defined elsewhere This will throw a trust failure exception. I tried allowing

Make Guzzle trust self-signed certificates?

TheStoryCoder Using the Guzzle HTTP client, I know you can set new GuzzleClient(['verify' => false])to not check the certificate, eg. When you use a self-signed certificate. But how do you make it accept and trust specific self-signed certificates so that you

Trust self-signed PEM certificates

Mother Teresa and the Teenager I have setup a proxy server with SSL using PEM certificate. Now, there are several machines where I would like this certificate to be automatically trusted (and the web browser doesn't complain). How to install PEM certificate on

Trust self-signed PEM certificates

Mother Teresa and the Teenager I have setup a proxy server with SSL using PEM certificate. Now, there are several machines where I would like this certificate to be automatically trusted (and the web browser doesn't complain). How to install PEM certificate on

Make Guzzle trust self-signed certificates?

TheStoryCoder Using the Guzzle HTTP client, I know you can set new GuzzleClient(['verify' => false])to not check the certificate, eg. When you use a self-signed certificate. But how do you make it accept and trust specific self-signed certificates so that you

Make Guzzle trust self-signed certificates?

TheStoryCoder Using the Guzzle HTTP client, I know you can set new GuzzleClient(['verify' => false])to not check the certificate, eg. When you use a self-signed certificate. But how do you make it accept and trust specific self-signed certificates so that you

Trust self-signed PEM certificates

Mother Teresa and the Teenager I have setup a proxy server with SSL using PEM certificate. Now, there are several machines where I would like this certificate to be automatically trusted (and the web browser doesn't complain). How to install PEM certificate on

Firefox doesn't trust self-signed certificates

username I'm trying to configure a computer to trust a self-signed certificate for testing a website. But I have a problem with Firefox. Chrome and IE work great. I have done the following. Create a 2048 bit Pem rsa key and create crt with openssl Created a pf

How to 'Trust' Self-Signed .dev Certificates on Ubuntu

McKinsey As we transition to using a purchased .dev domain for local development, I'm using the following code to generate a certificate: openssl req -x509 -out domain.dev.crt -keyout domain.dev.key \ -newkey rsa:2048 -nodes -sha256 \ -days 3650 \ -subj

How to 'Trust' Self-Signed .dev Certificates on Ubuntu

McKinsey As we transition to using a purchased .dev domain for local development, I'm using the following code to generate a certificate: openssl req -x509 -out domain.dev.crt -keyout domain.dev.key \ -newkey rsa:2048 -nodes -sha256 \ -days 3650 \ -subj

How to 'Trust' Self-Signed .dev Certificates on Ubuntu

McKinsey As we transition to using a purchased .dev domain for local development, I'm using the following code to generate a certificate: openssl req -x509 -out domain.dev.crt -keyout domain.dev.key \ -newkey rsa:2048 -nodes -sha256 \ -days 3650 \ -subj

How to 'Trust' Self-Signed .dev Certificates on Ubuntu

McKinsey As we transition to using a purchased .dev domain for local development, I'm using the following code to generate a certificate: openssl req -x509 -out domain.dev.crt -keyout domain.dev.key \ -newkey rsa:2048 -nodes -sha256 \ -days 3650 \ -subj

Only trust my self-signed certificate in httpclient

Marius I generated a self-signed certificate to use to authenticate my web app. Clients, not web browsers, use client applications to communicate with web servers. The client application uses httpclient. The internet is full of examples of how to trust all ssl

Only trust my self-signed certificate in httpclient

Marius I generated a self-signed certificate to use to authenticate my web app. Clients, not web browsers, use client applications to communicate with web servers. The client application uses httpclient. The internet is full of examples of how to trust all ssl

Ignore self-signed certificates in Apache 4.5 HTTPClient

Katie: I want to accept all certificates, and/or accept self-signed certificates using the Apache version of HTTPClient 4.5 (tutorial link here ) I've gone through a solution to the problem from a bunch of SO posts. So far none of them have worked. I keep gett

Can you use service workers with self-signed certificates?

Keith: I have developer server for testing. They have SSL self-signed certificates that allow us to test web applications over HTTPS, but with the obvious warning that the certificate is not verifiable. That's fine, but I have a service worker that throws an e

Only use self-signed SSL certificates for web services

Sconz2 I have a web service that the client will have and I want to encrypt the data sent to the server. To test this, I used a self-signed SSL certificate. I know that when you use a self-signed certificate and you navigate to any address that uses that certi

Can you use service workers with self-signed certificates?

Keith: I have developer server for testing. They have SSL self-signed certificates that allow us to test web applications over HTTPS, but with the obvious warning that the certificate is not verifiable. That's fine, but I have a service worker that throws an e

Tell Git to use multiple self-signed certificates as trusted

Mikhail Khorkov I have several git servers under several self-signed certificates. I need to add all certificates as trusted. I know about flag http.sslCAInfo- it only applies to one certificate. I know about flag http.sslCAPath- but it doesn't work at all. $

Only use self-signed SSL certificates for web services

Sconz2 I have a web service that the client will have and I want to encrypt the data sent to the server. To test this, I used a self-signed SSL certificate. I know that when you use a self-signed certificate and you navigate to any address that uses that certi

Can you use service workers with self-signed certificates?

Keith: I have developer server for testing. They have SSL self-signed certificates that allow us to test web applications over HTTPS, but with the obvious warning that the certificate is not verifiable. That's fine, but I have a service worker that throws an e