I'm attempting to make a web request that's failing because of a self signed certificate :
Client = new HttpClient();
HttpResponseMessage Response = await Client.GetAsync(Uri)//defined elsewhere
This throws a trust failure exception.
I tried again using httpclienthandler
as suggested here Allowing Untrusted SSL Certificates with HttpClient:
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 blows up throwing a system not implemented exception.
Are there any other ways to trust a self signed cert? I've even installed the certificate on the machine making the request but no luck.
I have seen so many question regarding this I figured I write up as a complete answer and example as I can.
Note: Using
WKWebView
with self-sign certs, see this answerHttpClient Implementation
Note: Using badssl.com in this example
Managed (Default)
The original Mono
Managed
provider is getting really long in the tooth and only supports TLS1.0, in terms of security & performance I would move to using the NSUrlSession implementation.CFNetwork (iOS 6+)
Note: As this iOS version is fairly old now and I personally do not target it anymore, so I leave this blank... (unless someone really needs me to lookup my notes for it ;-)
NSUrlSession (iOS 7+)
Xamarin provides a
HttpMessageHandler
subclass (NSUrlSessionHandler
) that is based upon iOS'NSUrlSession
.Using it by itself against a self-signed cert will result in:
The problem is that a self-sign cert is considered insecure and non-trusted by iOS, thus you have to apply an ATS exception to your app so iOS knows that your app is untrusted in the
Info.plist
.Now that iOS knows that your app is making untrusted calls, a
HttpClient
request will now result in this error:This error is due to the fact that even though the ATS exception has been allow, the default
NSUrlSession
provided by iOS will apply its standardNSUrlAuthenticationChallenge
to the certificate and fail since a self-signed cert can never be truly authenticated (even via client pinning) since it does not include a root certificate authority (CA) in its chain that is trusted by iOS.Thus you need to intercept and bypass the certificate security checking provided by iOS (Yes, a big security alert, flashing red lights, etc...)
But, you can do this via creating a
NSUrlSessionDataDelegate
subclass that does the bypass.Now you need to apply that
NSUrlSessionDataDelegate
to aNSUrlSession
and use that new session in the creation of yourNSUrlSessionHandler
that will be provided in the constructor of theHttpClient
.Note: Example only, normally you would create a single Delegate, NSUrlSession, HttpClient, NSUrlSessionHandler and re-use it for all your requests (i.e. Singleton pattern)
Your request now works:
Note: The option to supply your own custom
NSUrlSession
to Xamarin'sNSUrlSessionHandler
is really new (Nov. 2017) and not currently in a release build (alpha, beta or stable), but of course, source is available at:Using
NSUrlSession
instead ofHttpClient
:You can also directly use a
NSUrlSession
instead ofHttpClient
against a self-signed cert.Note: Example only, normally you would create a single Delegate and NSUrlSession and re-use it for all your requests, i.e. Singleton pattern
Real Solution? Use Free Secure Certificates:
IHMO, avoid self-signed certs all together, even in a development environment and use one of the free certificate services and avoid all the headaches of applying ATS exceptions, custom code to intercept/bypass iOS security, etc... and make your app web services actually secure.
I personally use Let’s Encrypt: