How to Validate SSL Certificates with .NET ServicePointManager

I’ve underestimated how frequently I must use a web API in my C# programs. If you’ve ever needed to send a web request from a.NET application, you’ve probably encountered the following annoying exception message just as often as I have.

Despite being so direct, this error message confuses the majority of developers. How do you fix it and what is the cause?

An invalid certificate on the target server typically results in an exception. By default,.NET web requests must confirm the target of their requests, and developers can use the ServicePointManager to verify an unknown certificate.

If you need something that “works”, then you might use the following code.

ServicePointManager.ServerCertificateValidationCallback +=
    (sender, certificate, chain, errors) => {
        return true;
    };
This hack should not be kept in your codebase, in my opinion. The above code poses a security risk because it will accept any certificate, including ones that are malicious. Continue reading if you want a better solution.

What Is The ServicePointManager

The Microsoft docs succinctly describes the purpose of the ServicePointManager class.

A ServicePoint object containing connection details for the host and scheme identified by the URI is returned by the ServicePointManager object in response to an application’s request to connect to an Internet resource with a Uniform Resource Identifier (URI).

For outgoing web requests, the class essentially functions as a connection manager. You must subscribe to the ServerCertificateValidationCallback event, which fires on each certificate validation, in order to verify these connections.

ServicePointManager For Development

Use this crude validator implementation if you’re writing a console program or other quick piece of code.

ServicePointManager.ServerCertificateValidationCallback +=
    (sender, certificate, chain, errors) =>
    {
        // local dev, just approve all certs
        if (development) return true;
        return errors == SslPolicyErrors.None ;
    };

The local development implementation ensures that the SSL policy is at the very least error-free.

ServicePointManager For Production

You can verify against a dictionary of certificate hashes if you believe the locations calling are legitimate and are aware of them. These certificates can either be read from disk or preloaded on the host computer. In the majority of situations, I prefer this second implementation of ServerCertificateValidationCallback.

ServicePointManager.ServerCertificateValidationCallback +=
    (sender, certificate, chain, errors) =>
    {
        // local dev, just approve all certs
        if (development) return true;
        return errors == SslPolicyErrors.None
            && validCerts.Contains(certificate.GetCertHashString());
    };

The hash strings of the X509 certificates you trust are contained in the dictionary that makes up the validCerts variable. These can be loaded from a database or a configuration file. The trusted certs can be loaded into a.NET console app, which can then output the hash strings.

var hash = X509Certificate
    .CreateFromCertFile("mycert.cer")
    .GetCertHashString();

By using trusted certificates, you can prevent any sensitive requests from being sent to untrusted servers. To minimize friction when beginning a development project, you can begin by accepting all certificates during local development; however, before deploying code into production, remember to harden your security.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *