How to ignore the certificate check when ssl
Asked Answered
N

16

163

I am trying find a way to ignore the certificate check when request a Https resource, so far, I found some helpful article in internet.

But I still have some problem. Please review my code. I just don't understand what does the code ServicePointManager.ServerCertificateValidationCallback mean.

When will this delegate method be called? And one more question, in which place should I write this code? Before ServicePointManager.ServerCertificateValidationCallback execute or before Stream stream = request.GetRequestStream()?

public HttpWebRequest GetRequest()
{
    CookieContainer cookieContainer = new CookieContainer();

    // Create a request to the server
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_remoteUrl);

    #region Set request parameters

    request.Method = _context.Request.HttpMethod;
    request.UserAgent = _context.Request.UserAgent;
    request.KeepAlive = true;
    request.CookieContainer = cookieContainer;
    request.PreAuthenticate = true;
    request.AllowAutoRedirect = false;

    #endregion

    // For POST, write the post data extracted from the incoming request
    if (request.Method == "POST")
    {
        Stream clientStream = _context.Request.InputStream;
        request.ContentType = _context.Request.ContentType;
        request.ContentLength = clientStream.Length;

        ServicePointManager.ServerCertificateValidationCallback = delegate(
            Object obj, X509Certificate certificate, X509Chain chain, 
            SslPolicyErrors errors)
            {
                return (true);
            };

            Stream stream = request.GetRequestStream();

            ....
        }

        ....

        return request;
    }
}   
Nydianye answered 20/9, 2012 at 5:33 Comment(1)
Possible duplicate of C# Ignore certificate errors?Livraison
P
74

Since there is only one global ServicePointManager, setting ServicePointManager.ServerCertificateValidationCallback will yield the result that all subsequent requests will inherit this policy. Since it is a global "setting" it would be prefered to set it in the Application_Start method in Global.asax.

Setting the callback overrides the default behaviour and you can yourself create a custom validation routine.

Plenum answered 20/9, 2012 at 6:26 Comment(10)
What about for a client that has no Global.asax? I am calling a REST service running on the local network from a handheld device.Oversexed
The question is specific to HttpWebRequest. If you're using any other means you'll have to look in the documentation how to accomplish this.Plenum
I'm using WebRequest, which gets cast to HttpWebRequest, such as: ((HttpWebRequest)request).Accept = contentType;Oversexed
As stated in my answer: it is PREFERRED to set it in Global.asax not a requirement. You can even set it before the call to the REST service.Plenum
Unfortunately, in my case, ServerCertificateValidationCallback is unavailable. If interested, see Updates 2 and 3 here: #27643214Oversexed
See this link for a possible solution.Plenum
Using the global method, is there a way to reset it so it again validates after setting? The per request answers below will not work in the project I am working on.Tabular
@user3290142: ServicePointManager.ServerCertificateValidationCallback = null; should do the trick. Or perhaps store the old callback var oldSCVC = ServicePointManager.ServerCertificateValidationCallback;, change it, make your call and then restore it: ServicePointManager.ServerCertificateValidationCallback = oldSCVC;. Try them out. (Per request obviously uses the request object instead of the global).Plenum
@SaniSinghHuttunen thanks. I tried what you said but did not have complete success. ServicePointManager.ServerCertificateValidationCallback is null to start with, so there is no initial callback to save off. If I make a connection ignoring SSL, the setting seems to stick regardless of setting the callback to null. If I make a second connection to a different IP and clear the callback, SSL is checked but only for that connection NOT the initial connection.Tabular
Hi @SaniSinghHuttunen ,I am using this delegate (ServicePointManager.ServerCertificateValidationCallback ) always returning true and suddenly start getting this exception "The request failed. The underlying connection was closed: An unexpected error occurred on a send." , unable to find what causing this. can you please guide in this case?Messapian
D
211

For anyone interested in applying this solution on a per request basis, this is an option and uses a Lambda expression. The same Lambda expression can be applied to the global filter mentioned by blak3r as well. This method appears to require .NET 4.5.

String url = "https://www.stackoverflow.com";
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

In .NET 4.0, the Lambda Expression can be applied to the global filter as such

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
Dashboard answered 4/9, 2013 at 21:47 Comment(8)
Is there any per-request solution for FtpWebRequest?Salonika
It seems to exist fine in my 4.0Aponeurosis
I think is by far a nicer solution to the 'global' variant, although of course I can understand why you would want it. Personally I favour a request factory which then manages this validation callback. Thanks Adam, nice solution.Orms
Returning true is something you can do when experimenting during development, however it is insecure. It should be a conditional.Gredel
It seems that WebRequest.CreateHttp has been removed after .NET 4.0. var request = (HttpWebRequest)WebRequest.Create(url) is the way to go.Gean
Using (HttpWebRequest)WebRequest.Create(url) is perfectly valid, but on my box, HttpWebRequest.Create(url) still exists in a project targeting .Net 4.6.2. Chef's choice, but at this point HttpClient is probably the better API to use.Dashboard
In my case, the server's certificate has no trusted CA signing it, and the callback never gets invoked! And I cannot add CA's in an Azure Web App. I have been stuck with this problem for 3 days! any ideas here? #49910010Sebastian
@JoãoAntunes I'm sorry, I don't know how to handle that case.Dashboard
P
74

Since there is only one global ServicePointManager, setting ServicePointManager.ServerCertificateValidationCallback will yield the result that all subsequent requests will inherit this policy. Since it is a global "setting" it would be prefered to set it in the Application_Start method in Global.asax.

Setting the callback overrides the default behaviour and you can yourself create a custom validation routine.

Plenum answered 20/9, 2012 at 6:26 Comment(10)
What about for a client that has no Global.asax? I am calling a REST service running on the local network from a handheld device.Oversexed
The question is specific to HttpWebRequest. If you're using any other means you'll have to look in the documentation how to accomplish this.Plenum
I'm using WebRequest, which gets cast to HttpWebRequest, such as: ((HttpWebRequest)request).Accept = contentType;Oversexed
As stated in my answer: it is PREFERRED to set it in Global.asax not a requirement. You can even set it before the call to the REST service.Plenum
Unfortunately, in my case, ServerCertificateValidationCallback is unavailable. If interested, see Updates 2 and 3 here: #27643214Oversexed
See this link for a possible solution.Plenum
Using the global method, is there a way to reset it so it again validates after setting? The per request answers below will not work in the project I am working on.Tabular
@user3290142: ServicePointManager.ServerCertificateValidationCallback = null; should do the trick. Or perhaps store the old callback var oldSCVC = ServicePointManager.ServerCertificateValidationCallback;, change it, make your call and then restore it: ServicePointManager.ServerCertificateValidationCallback = oldSCVC;. Try them out. (Per request obviously uses the request object instead of the global).Plenum
@SaniSinghHuttunen thanks. I tried what you said but did not have complete success. ServicePointManager.ServerCertificateValidationCallback is null to start with, so there is no initial callback to save off. If I make a connection ignoring SSL, the setting seems to stick regardless of setting the callback to null. If I make a second connection to a different IP and clear the callback, SSL is checked but only for that connection NOT the initial connection.Tabular
Hi @SaniSinghHuttunen ,I am using this delegate (ServicePointManager.ServerCertificateValidationCallback ) always returning true and suddenly start getting this exception "The request failed. The underlying connection was closed: An unexpected error occurred on a send." , unable to find what causing this. can you please guide in this case?Messapian
B
59

This worked for me:

System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                        System.Security.Cryptography.X509Certificates.X509Chain chain,
                        System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        return true; // **** Always accept
    };

Snippet from here: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors

Brezin answered 29/4, 2013 at 22:38 Comment(3)
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;Unofficial
Always returning true is insecure. It should conditionally return true.Gredel
This is per-process, so it is not safe.Halloran
C
30

Also there is the short delegate solution:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 
Cano answered 13/8, 2015 at 12:57 Comment(5)
Always returning true is insecure.Gredel
Yes, always trusting all SSL certificates is insecure by definition. Avoid doing so if possible.Cano
@AndrejRommel what is your way recommended?Pharmaceutics
The recommended way is to create a valid SSL certificate and properly utilize it if you have control over the server. We ended up creating one using letsencrypt.org.Cano
@AndrejRommel Interesting enough I'm getting this with a HttpWebRequest and it's suddenly throwing exceptions related to this, but the cert is good, I wish more articles explained the mechanism behind what HttpWebRequest is validating that others are not, but everything just says to turn it off, which I know is wrong!Inchon
M
10

Just incidentally, this is a the least verbose way of turning off all certificate validation in a given app that I know of:

ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
Mcdaniel answered 4/2, 2016 at 23:29 Comment(0)
M
9

For .net core

using (var handler = new HttpClientHandler())
{ 
    // allow the bad certificate
    handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => true;
    using (var httpClient = new HttpClient(handler))
    {
        await httpClient.PostAsync("the_url", null);
    }
}
Monaghan answered 14/5, 2020 at 17:0 Comment(1)
Thank you for the .net core solution!Render
C
7

Rather than adding a callback to ServicePointManager which will override certificate validation globally, you can set the callback on a local instance of HttpClient. This approach should only affect calls made using that instance of HttpClient.

Here is sample code showing how ignoring certificate validation errors for specific servers might be implemented in a Web API controller.

using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public class MyController : ApiController
{

    // use this HttpClient instance when making calls that need cert errors suppressed
    private static readonly HttpClient httpClient;

    static MyController()
    {
        // create a separate handler for use in this controller
        var handler = new HttpClientHandler();

        // add a custom certificate validation callback to the handler
        handler.ServerCertificateCustomValidationCallback = ((sender, cert, chain, errors) => ValidateCert(sender, cert, chain, errors));

        // create an HttpClient that will use the handler
        httpClient = new HttpClient(handler);
    }

    protected static ValidateCert(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
    {

        // set a list of servers for which cert validation errors will be ignored
        var overrideCerts = new string[]
        {
            "myproblemserver",
            "someotherserver",
            "localhost"
        };

        // if the server is in the override list, then ignore any validation errors
        var serverName = cert.Subject.ToLower();
        if (overrideCerts.Any(overrideName => serverName.Contains(overrideName))) return true;

        // otherwise use the standard validation results
        return errors == SslPolicyErrors.None;
    }

}
Clower answered 18/12, 2018 at 16:46 Comment(3)
Won't this only work for .NET Core? (Or whenever ServerCertificateCustomValidationCallback was added to HttpClientHandler)?Grubbs
This solution should work in .Net Framework 4.5 and later as well as .Net Core (although I have not tested it in .Net Core).Clower
@Sheldon, this was a gem :) Used in in my localhost api-calls between a .net and a .net core app with success. Nice workaround without accepting all.Donelson
G
5

Mention has been made that before .NET 4.5 the property on the request to access its ServicePointManager was not available.

Here is .NET 4.0 code that will give you access to the ServicePoint on a per-request basis. It doesn't give you access to the per-request callback, but it should let you find out more details about the problem. Just access the scvPoint.Certificate (or ClientCertificate if you prefer) properties.

WebRequest request = WebRequest.Create(uri);

// oddity: these two .Address values are not necessarily the same!
//  The service point appears to be related to the .Host, not the Uri itself.
//  So, check the .Host vlaues before fussing in the debugger.
//
ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);
if (null != svcPoint)
{
    if (!request.RequestUri.Host.Equals(svcPoint.Address.Host, StringComparison.OrdinalIgnoreCase))
    {
        Debug.WriteLine(".Address              == " + request.RequestUri.ToString());
        Debug.WriteLine(".ServicePoint.Address == " + svcPoint.Address.ToString());
    }
    Debug.WriteLine(".IssuerName           == " + svcPoint.Certificate.GetIssuerName());
}
Garlen answered 6/3, 2014 at 17:43 Comment(2)
Agreed! But then, this OP is about how to ignore them, not trust them.Garlen
Anyways, Using ServicePoint I cannot always trusting all SSL certificates, neither ignore all certificates, because has not ServerCertificateValidationCallback delegate in ServicePointPharmaceutics
W
5

CA5386 : Vulnerability analysis tools will alert you to these codes.

Correct code :

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
{
   return (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != SslPolicyErrors.RemoteCertificateNotAvailable;
};
Wornout answered 29/7, 2019 at 2:9 Comment(0)
G
4

Based on Adam's answer and Rob's comment I used this:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => certificate.Issuer == "CN=localhost";

which filters the "ignoring" somewhat. Other issuers can be added as required of course. This was tested in .NET 2.0 as we need to support some legacy code.

Glance answered 8/5, 2014 at 7:12 Comment(1)
@karank Sorry for late reply - It can be added anywhere before the actual call, eg. before calling request.GetResponse(). Note that Issuer might contain something else in your case though.Glance
M
3

Unity C# Version of this solution:

void Awake()
{
    System.Net.ServicePointManager.ServerCertificateValidationCallback += ValidateCertification;
}

void OnDestroy()
{
    ServerCertificateValidationCallback = null;
}

public static bool ValidateCertification(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    return true;
}
Mamba answered 3/3, 2020 at 12:13 Comment(1)
Upvote this because Unity throws on any get or set of handler.ServerCertificateCustomValidationCallbackClassical
W
2

Expressed explicitly ...

ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(CertCheck);

private static bool CertCheck(object sender, X509Certificate cert,
X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
    return true;
}
Wornout answered 15/4, 2019 at 1:9 Comment(0)
F
2

On .NetCore 3.1 you can resolve this issue by declaring a custom validation method.

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };  
  

So before making a request, declare this callback method

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };    
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://someurl.com/service/");  
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();  
  

This way, validation will always pass as your custom method always returns true value.

Fania answered 13/5, 2021 at 15:18 Comment(0)
T
1

Several answers above work. I wanted an approach that I did not have to keep making code changes and did not make my code unsecure. Hence I created a whitelist. Whitelist can be maintained in any datastore. I used config file since it is a very small list.

My code is below.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, error) => {
    return error == System.Net.Security.SslPolicyErrors.None || certificateWhitelist.Contains(cert.GetCertHashString());
};
Transpontine answered 15/10, 2018 at 19:57 Comment(0)
E
0

Adding to Sani's and blak3r's answers, I've added the following to the startup code for my application, but in VB:

'** Overriding the certificate validation check.
Net.ServicePointManager.ServerCertificateValidationCallback = Function(sender, certificate, chain, sslPolicyErrors) True

Seems to do the trick.

Exocarp answered 5/7, 2013 at 22:15 Comment(0)
O
0

Tip: You can also use this method to track certificates that are due to expire soon. This can save your bacon if you discover a cert that is about to expire and can get it fixed in time. Good also for third party companies - for us this is DHL / FedEx. DHL just let a cert expire which is screwing us up 3 days before Thanksgiving. Fortunately I'm around to fix it ... this time!

    private static DateTime? _nextCertWarning;
    private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
    {
        if (error == SslPolicyErrors.None)
        {
            var cert2 = cert as X509Certificate2;
            if (cert2 != null)
            { 
                // If cert expires within 2 days send an alert every 2 hours
                if (cert2.NotAfter.AddDays(-2) < DateTime.Now)
                {
                    if (_nextCertWarning == null || _nextCertWarning < DateTime.Now)
                    {
                        _nextCertWarning = DateTime.Now.AddHours(2);

                        ProwlUtil.StepReached("CERT EXPIRING WITHIN 2 DAYS " + cert, cert.GetCertHashString());   // this is my own function
                    }
                }
            }

            return true;
        }
        else
        {
            switch (cert.GetCertHashString())
            {
                // Machine certs - SELF SIGNED
                case "066CF9CAD814DE2097D367F22D3A7E398B87C4D6":    

                    return true;

                default:
                    ProwlUtil.StepReached("UNTRUSTED CERT " + cert, cert.GetCertHashString());
                    return false;
            }
        }
    }
Oly answered 21/11, 2017 at 19:18 Comment(3)
Make sure to handle the situation where your alerting mechanism can have an expired cert - or you'll end up with a stackoverflow!Oly
What is ProwlUtil.StepReached ?Pharmaceutics
Sorry that’s just my own method to call the Prowl API which can send notifications to my phone. However you want to log it is good. I like to be bugged on my phone for things like this!Oly

© 2022 - 2024 — McMap. All rights reserved.