Restore SSL certificate override check
I am writing a test to test a service I am deploying, to bypass the ssl cert check I implemented an ssl override using the snippet below:
public static void SSLValidationOverride()
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(OnValidationCallback);
}
private static bool OnValidationCallback(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
{
if (cert.subject == MyCertSubject)
return true;
else
return false;
}
Now I have to call another webservice using ssl in the code and want to switch to default ssl check before calling that. What's the best way to do that. MS help says the default value of ServicePointManager开发者_StackOverflow.SecurityProtocol is null(http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.securityprotocol.aspx). Will setting it to null switch to default ssl validation and is there any other way to do this.
I have ran in to a similar problem during the development of a diagnostics tool I have created. I have created a windows service that makes requests to a list of urls. For each url I make a request without certificate validation by setting this:
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
and then with the same url I also attempt to make a request with certificate validation by resetting the property back to null which should provide the default functionality:
ServicePointManager.ServerCertificateValidationCallback = null;
This has had unexpected results as my request is still made without certificate validation as if the reset has been ignored. After debugging I found that if I waited for long enough after setting
ServicePointManager.ServerCertificateValidationCallback = null;
then it was actually reset and my request was made with default certificate validation. so I simply put a sleep in for 30 seconds before I made the request:
ServicePointManager.ServerCertificateValidationCallback = null;
System.Threading.Thread.Sleep(30000);
//Make request here
I don't understand why this works but it does and I'm sure there is a better way of doing it and if you know how then please let me know.
Setting the callback to null does not work. Instead all certs pass. I don't understand why so many people have posted setting the value to null works or -= works. Neither do the job...at least in 3.5. After futher testing it seems as though the check is simply cached. Re-checking once the cert has been validated once does not cause the callback to get called.
I ended up setting ServicePointManager.SecurityProtocol to null and it works fine. Though am still open to better ways to do this
public static void SSLValidationRestore()
{
ServicePointManager.ServerCertificateValidationCallback = null;
}
I ran into a similar problem. Instead of calling Thread.Sleep() on @Acode Monkey solution, you could change the ServicePointManager.MaxServicePointIdleTime to a low value.
ServicePointManager.MaxServicePointIdleTime = 1;
Setting callback to null can be OK, but connections already made are still in use. So certificate for them is not checked for about 30 seconds as @Acode Monkey stated.
There is a way how to tell that connections should not be used for so long - as stated in @Kyibe answer. But for me it was not working at 100% cases.
So i write a little helper, who does all this for me:
internal static class ServiceHelper
{
/// <summary>
/// Gets or sets whether to ignore certificate errors.
/// </summary>
public static bool IgnoreCertificateErrors
{
get => _ignoreCertificateErrors;
set => _ignoreCertificateErrors = value;
}
/// <summary>
/// Gets or sets whether to ignore certificate errors.
/// This property is static because it controls the ServicePointManager settings, and that is static.
/// </summary>
private static volatile bool _ignoreCertificateErrors = true;
/// <summary>
/// Callback for certificate validation event, which based on <see cref="_ignoreCertificateErrors"/> will let invalid certificates pass or not.
/// </summary>
private static bool ValidateCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
{
if (_ignoreCertificateErrors)
return true;
// default behavior
return sslpolicyerrors == SslPolicyErrors.None;
}
/// <summary>
/// Calling this method will ensure that certificate validation will be covered by <see cref="IgnoreCertificateErrors" /> property.
/// </summary>
public static void EnsureCustomCertificateValidation()
{
var callbackCount = ServicePointManager.ServerCertificateValidationCallback?.GetInvocationList().Length ?? 0;
// adding callback only if there is no callback already
if (callbackCount == 0)
{
// due to this setting will connection stay active no longer than 1s (so method ValidateCertificate will be called for every action if they are at least 1 second split)
ServicePointManager.MaxServicePointIdleTime = 1000; //ms
// setting the certificate validaction callback
ServicePointManager.ServerCertificateValidationCallback += ValidateCertificate;
}
}
}
And then simply call ServiceHelper.EnsureCustomCertificateValidation()
before using any WebService or whatever.
You can easily then switch between Ignoring certificate errors and default behavior
精彩评论