Allowing Untrusted SSL Certificates with HttpClient
With Windows 8.1, you can now trust invalid SSL certs. You have to either use the Windows.Web.HttpClient or if you want to use the System.Net.Http.HttpClient, you can use the message handler adapter I wrote:
http://www.nuget.org/packages/WinRtHttpClientHandler
Docs are on the GitHub:
https://github.com/onovotny/WinRtHttpClientHandler
bypass invalid SSL certificate in .net core
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
How to allow all https regardless of validity in .NET Core HttpClient?
Use the sample below from here
var httpClientHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpClientHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(httpClientHandler);
Trust a self signed certificate using Httpclient
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 answer
HttpClient Implementation
Note: Using badssl.com in this example
Managed (Default)
System.Net.Http.HttpRequestException: An error occurred while sending the request --->
System.Net.WebException: Error: TrustFailure (One or more errors occurred.) --->
System.AggregateException: One or more errors occurred. --->
System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. --->
Mono.Security.Interface.Tl
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:
System.Net.WebException: An SSL error has occurred and a secure connection to the server cannot be made. --->
Foundation.NSErrorException:
Exception of type 'Foundation.NSErrorException' was thrown.
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
.
<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 that your app is making untrusted calls, a HttpClient
request will now result in this error:
System.Net.WebException: The certificate for this server is invalid. You might be connecting to a server that is pretending to be‚ self-signed.badssl.com‚ which could put your confidential information at risk. --->
Foundation.NSErrorException: Exception of type 'Foundation.NSErrorException' was thrown.
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 standard NSUrlAuthenticationChallenge
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.
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 that NSUrlSessionDataDelegate
to a NSUrlSession
and use that new session in the creation of your NSUrlSessionHandler
that will be provided in the constructor of the 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: 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:
<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>
Note: The option to supply your own custom NSUrlSession
to Xamarin's NSUrlSessionHandler
is really new (Nov. 2017) and not currently in a release build (alpha, beta or stable), but of course, source is available at:
- xamarin-macios/src/Foundation/NSUrlSessionHandler.cs
Using NSUrlSession
instead of HttpClient
:
You can also directly use a NSUrlSession
instead of HttpClient
against a self-signed cert.
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: 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:
- https://letsencrypt.org
Ignoring SSL certificate in Apache HttpClient 4.3
The code below works for trusting self-signed certificates. You have to use the TrustSelfSignedStrategy when creating your client:
SSLContextBuilder builder = new SSLContextBuilder();
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
builder.build());
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(
sslsf).build();
HttpGet httpGet = new HttpGet("https://some-server");
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} finally {
response.close();
}
I did not include the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
on purpose: The point was to allow testing with self signed certificates so you don't have to acquire a proper certificate from a certification authority. You can easily create a self-signed certificate with the correct host name, so do that instead of adding the SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
flag.
How can I disable the SSL Certificate check in the .NET Core http client?
TL; DR: The problem lied not within certificate validation, but in a security group rule.
- As Marc Gravell kindly pointed out, the
DangerousAcceptAnyServerCertificateValidator
already achieves the aim of ignoring certificate validation problems. - After deploying the same code in an EC2 instance in the same VPC and subnet I noticed, that the .NET Core code was making one more HTTP call than the Go code (Although I still do not understand why). The IP adress was not within the allowed IP range of outgoing traffic, thus blocking the request and causing a timeout of the
HttpClient
.
How to ignore SSL policy to perform a HTTPClient request?
Consider trying it like this
//Handle TLS protocols
System.Net.ServicePointManager.SecurityProtocol =
System.Net.SecurityProtocolType.Tls
| System.Net.SecurityProtocolType.Tls11
| System.Net.SecurityProtocolType.Tls12;
var client = new HttpClient();
client.BaseAddress = new Uri("https://myapi");
//...
var result = await client.PostAsync(method, httpContent);
Related Topics
What Is the Purpose of a Marker Interface
How to Set a Property Value with Reflection
Allowing Untrusted Ssl Certificates with Httpclient
Regex for Accepting Only Persian Characters
Get Mime Type from Filename Extension
How to Get Current User in ASP.NET Core
Checking for Null Before Event Dispatching... Thread Safe
Arrays, Heap and Stack and Value Types
How to Do Pagination in Datagridview in Winform
How to Detect the Character Encoding of a Text File
What Does the '=>' Syntax in C# Mean
Single Controller with Multiple Get Methods in ASP.NET Web API
Add Data Annotations to a Class Generated by Entity Framework