I am working on a project that uses some HTTP communication between two back-end servers. Servers are using X509 certificates for authentication. Needless to say, when server A (client) establishes connection to server B (server), there is a SSL/TLS validation error, since certificates used are not from trusted 3rd party authority.
Normally, the way to handle it is using ServicePointManager.ServerCertificateValidationCallback
, such as:
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, error) =>
{
return cert.GetCertHashString() == "xxxxxxxxxxxxxxxx";
};
That approach works, except it's not ideal. What it essentially does is override validation procedure for EVERY http request done by the application. So, if another class will try to run HTTP request, it will fail. Also, if another class overrides ServicePointManager.ServerCertificateValidationCallback
for its own purposes, then my communication starts failing out of sudden.
The only solution which comes to mind, is creating a separate AppDomain to perform client HTTP requests. That would work, but really - it's silly to have to do that only so that one can perform HTTP requests. Overhead will be staggering.
With that in mind, have anyone researched if there is a better practice in .NET, which would allow accessing web services, while handling client SSL/TLS validation without affecting other web clients?
Remarks. An application can set the ServerCertificateValidationCallback property to a method to use for custom validation by the client of the server certificate.
An SSL certificate is a bit of code on your web server that provides security for online communications. When a web browser contacts your secured website, the SSL certificate enables an encrypted connection. It's kind of like sealing a letter in an envelope before sending it through the mail.
An acceptable (safe) methodology working in .NET 4.5+ is to use HttpWebRequest.ServerCertificateValidationCallback
. Assigning that callback on a specific instance of request will change the validation logic just for the request, not influencing other requests.
var request = (HttpWebRequest)WebRequest.Create("https://...");
request.ServerCertificateValidationCallback +=
(sender, cert, chain, error) =>
{
return cert.GetCertHashString() == "xxxxxxxxxxxxxxxx";
};
An alternative for code that does not use HttpWebRequest, and for environments where you can't install trusted certificates in the certificate store: Check the callback's error parameter, which will contain any error that were detected prior to the callback. This way, you can ignore errors for specific hash strings, but still accept other certificates that pass validation.
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, error) =>
{
if (cert.GetCertHashString() == "xxxxxxxxxxxxxxxx")
{
return true;
}
else
{
return error == SslPolicyErrors.None;
}
};
Reference: https://msdn.microsoft.com/en-us/library/system.net.security.remotecertificatevalidationcallback(v=vs.110).aspx
Note that this will still affect other web client instances in the same appdomain (they will all accept the specified hash string), but at least it won't block other certificates.
The straight-forward approach for this scenario should be to install the two self-generated certificates in the trusted root stores on the client machines. You will get a security warning when you do this because the certificates can't be authenticated with Thawte or similar but after that regular secure communication should work. IIRC, you need to install the full (both public and private key) version in trusted root for this to work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With