代码之家  ›  专栏  ›  技术社区  ›  atconway

如何将“ServerCertificateValidationCallback”属性设置回其默认行为?

  •  16
  • atconway  · 技术社区  · 14 年前

    我在单个方法中使用以下代码行来显式检查和信任来自以下主机的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”对象上的共享属性,然后必须为整个应用程序持久化,这是我不想要的。

    问题是后来我打电话给我的网络服务等,得到了“无法建立信任关系…”的例外。这是因为在上面的代码行中,我检查了该方法的ssl cert specefic的主机名。我很快测试了从回调返回“true”,这样所有证书都将被信任,而不是检查特定名称(即myTrustedCompany)和子队列请求。 工作 . 这就是我如何知道这个回调分配比那个单一方法到达父级的原因。当然,我可以扩展回调以包括所有其他证书名称,但我会怎么做 相当地 将“ServerCertificateValidationCallback”设置回其默认行为。如下面的伪代码:

    ServicePointManager.ServerCertificateValidationCallback = Nothing  'Default checking behavior
    

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

    4 回复  |  直到 10 年前
        1
  •  13
  •   atconway    14 年前

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

    ServicePointManager.ServerCertificateValidationCallback = Nothing
    
        2
  •  4
  •   Tom    13 年前

    对于某些URL,您只希望返回true, 但是,否则,这会满足您的需要,留下使用多个委托的可能性。每个回调的逻辑可以包括一个通过反射进行的检查,以便回调仅在从某些组件调用时返回true,从而在某些URL和某些应用程序之间创建一种隧道。

    使用此代码的一种方法: 1。在对象生命早期定义mignorebadcertificates委托 2。设置包含“besecure”代码的属性为true 三。发送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");
        }
    
        3
  •  3
  •   Tom Winter    11 年前

    解决问题的关键是 sender 参数 RemoteCertificateValidationCallback 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;
            }
        }
    }
    
        4
  •  1
  •   OzBob    10 年前
    public class OAuthRequestHandler : WebRequestHandler
    {
        public OAuthRequestHandler() : base()
        {
            base.ServerCertificateValidationCallback  += this.InternalCallback;
        }
    
        private bool InternalCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return certificate.Subject.Contains("CN=MyTrustedCompany.com");
        }
    }
    

    在my program.cs命令行测试中:

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

    可以对证书和发送者参数做更多的操作,但OP要求进行以上操作。