.net 如何设置';ServerCertificateValidationCallback';属性返回其默认行为?

.net 如何设置';ServerCertificateValidationCallback';属性返回其默认行为?,.net,vb.net,ssl,ssl-certificate,.net,Vb.net,Ssl,Ssl Certificate,我在一个方法中使用以下代码行显式检查并信任来自以下主机的SSL证书:MyTrustedCompany.com: ServicePointManager.ServerCertificateValidationCallback = Function(obj As [Object], certificate As X509Certificate, chain As X509Chain, errors As SslPolicyErrors) (certificate.Subject.Contains("

我在一个方法中使用以下代码行显式检查并信任来自以下主机的SSL证书:MyTrustedCompany.com:

ServicePointManager.ServerCertificateValidationCallback = Function(obj As [Object], certificate As X509Certificate, chain As X509Chain, errors As SslPolicyErrors) (certificate.Subject.Contains("CN=MyTrustedCompany.com"))
代码没有问题->100%完美工作

问题是,这太深远了。我以为它的作用域只在我贴花它的方法中,但显然它是“ServicePointManager”对象上的一个共享属性,并且必须在整个应用程序中保持,这是我不想要的

问题是后来我调用了我的web服务等,并得到“无法建立信任关系…”异常。这是因为在上面的代码行中,我检查了该方法的SSL证书specefic的主机名。我很快测试了从回调返回“True”,这样所有证书都会被信任,而不是检查特定的名称(即MyTrustedCompany)和子请求是否有效。这就是为什么我知道这个回调分配比那个单一方法更有效。当然,我可以扩展回调以包括所有其他Certificate名称,但我更愿意做的是将“ServerCertificateValidationCallback”设置回其默认行为。如下面的伪代码所示:

ServicePointManager.ServerCertificateValidationCallback = Nothing  'Default checking behavior

如何删除自定义验证并将其设置回默认行为?谢谢

这实际上看起来是可行的(尽管很简单),并使对象以其默认方式运行

ServicePointManager.ServerCertificateValidationCallback = Nothing

对于某些URL,您只希望返回true, 但除此之外,这会满足您的需要,从而保留使用多个代理的可能性。每个回调的逻辑可以包括一个通过反射的检查,这样回调只在从某些组件调用时返回true,从而在某些URL和某些应用程序之间创建一种隧道

使用此代码的一种方法: 1.在对象生命早期定义mIgnoreBadCertificates委托 2.将包含“beSecure”代码的属性设置为true 3.发送Http请求。 4.将属性设置为false。这是非常重要的,应该以一种保证调用它的方式来实现。IDisposable模式是一个选项

 private System.Net.Security.RemoteCertificateValidationCallback mIgnoreBadCertificates = new
    System.Net.Security.RemoteCertificateValidationCallback(
      delegate { return true; });

if (beSecure)
    {   //require secure communications
        System.Net.ServicePointManager.ServerCertificateValidationCallback -= mIgnoreBadCertificates;
        Iwds.EventLogger.LogVeryFrequentEvent("Requiring Good Certificates from Remote Sites");
    }
    else
    {   /// Allow connections to SSL sites that have unsafe certificates.
        System.Net.ServicePointManager.ServerCertificateValidationCallback += mIgnoreBadCertificates;
        Iwds.EventLogger.LogVeryFrequentEvent("Ignoring Bad Certificates from Remote Sites");
    }

解决问题的一个关键点是
RemoteCertificateValidationCallback
sender
参数是
WebRequest
。您可以根据您的webrequest检查发件人,因此您只需检查您的webrequest。以下是我的(相对未经测试的)解决方案:

// Main Code

request = (FtpWebRequest)FtpWebRequest.Create("ftp://example.com");

using(var validator = new WebRequestCertificateValidator(request))
{
    // etc...
}

// WebRequestCertificateValidator Class

public sealed class WebRequestCertificateValidator : IDisposable
{
    private bool disposed;

    private WebRequest request;

    private RemoteCertificateValidationCallback callback;

    /// <summary>
    /// Creates a certificate validator that allows all certificates for the supplied web request.
    /// </summary>
    /// <param name="request">The WebRequest to validate for.</param>
    public WebRequestCertificateValidator(WebRequest request) : this(request, null)
    {
        //
    }

    /// <summary>
    /// Creates a certificate validator that only allows certificates for the supplied web request of the callback returns true.
    /// </summary>
    /// <param name="request">The WebRequest to validate for.</param>
    /// <param name="callback">The delegate that will be called to validate certificates for the WebRequest.</param>
    public WebRequestCertificateValidator(WebRequest request, RemoteCertificateValidationCallback callback)
    {
        this.disposed = false;

        this.request = request;

        this.callback = callback;

        ServicePointManager.ServerCertificateValidationCallback += this.InternalCallback;
    }

    private bool InternalCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        WebRequest request = sender as WebRequest;

        if(request != null)
        {
            if(request == this.request)
            {
                if(this.callback != null)
                {
                    return this.callback(sender, certificate, chain, sslPolicyErrors);
                }
            }
        }

        return true;
    }

    public void Dispose()
    {
        if(!this.disposed)
        {
            ServicePointManager.ServerCertificateValidationCallback -= this.InternalCallback;

            this.callback = null;

            this.request = null;

            this.disposed = true;
        }
    }
}
//主代码
请求=(FtpWebRequest)FtpWebRequest.Create(“ftp://example.com");
使用(var验证器=新WebRequestCertificateValidator(请求))
{
//等等。。。
}
//WebRequestCertificateValidator类
公共密封类WebRequestCertificateValidator:IDisposable
{
私人住宅;
私人网络请求;
私有RemoteCertificateValidationCallback;
/// 
///创建一个证书验证器,该验证器允许提供的web请求的所有证书。
/// 
///要验证的WebRequest。
公共WebRequestCertificateValidator(WebRequest请求):此(请求,null)
{
//
}
/// 
///创建一个证书验证器,该验证器只允许提供的回调web请求的证书返回true。
/// 
///要验证的WebRequest。
///将被调用以验证WebRequest证书的委托。
公共WebRequestCertificateValidator(WebRequest请求、RemoteCertificateValidationCallback回调)
{
这是错误的;
this.request=请求;
this.callback=回调;
ServicePointManager.ServerCertificateValidationCallback+=this.InternalCallback;
}
私有bool内部回调(对象发送方、X509证书证书、X509链、SslPolicyErrors SslPolicyErrors)
{
WebRequest request=发件人作为WebRequest;
if(请求!=null)
{
if(request==this.request)
{
if(this.callback!=null)
{
返回此.callback(发送方、证书、链、sslPolicyErrors);
}
}
}
返回true;
}
公共空间处置()
{
如果(!this.disposed)
{
ServicePointManager.ServerCertificateValidationCallback-=this.InternalCallback;
this.callback=null;
this.request=null;
这是真的;
}
}
}
在我的program.cs命令行测试中:

HttpClient client = new HttpClient(new OAuthRequestHandler());
responseString = await client.GetStringAsync("https://localhost:2345");

可以对证书和发送方参数进行更多操作,但OP要求执行上述操作。

唯一可靠的方法是确保自定义回调被可靠地还原,并且整个过程也是线程安全的,将需要被破坏回调的代码放入单独的进程中。在许多情况下,这是很容易做到的——例如,您可以使用
process
类运行单独的流程代码,并向其传递命令行。gRPC或WCF是其他通信选项


这样,只有单独的进程设置自定义回调,主进程不受影响。

您可以将其设置为一个函数,该函数执行默认行为:当不使用自定义验证时,将证书名称与用于创建请求的主机名进行比较。例如,如果向Create(String)传递了参数“”,则默认行为是客户端根据www.contoso.com检查证书。一个类似的问题有一个很好的答案,你知道有没有什么方法可以让这个线程安全吗?因为这个东西是静态的,我假设,每个使用web服务的线程都会在设置委托时调用它(意识到这是非常古老的…),你确定这样行吗?在C#中设置为null。是的,它可以将行为设置回默认值,这样它就可以开始discrim了
HttpClient client = new HttpClient(new OAuthRequestHandler());
responseString = await client.GetStringAsync("https://localhost:2345");