2010-11-11 93 views
16

我用一個單一的方法中的以下代碼行明確檢查並從以下主機信任的SSL證書:MyTrustedCompany.com:如何將「ServerCertificateValidationCallback」屬性恢復爲默認行爲?

ServicePointManager.ServerCertificateValidationCallback = Function(obj As [Object], certificate As X509Certificate, chain As X509Chain, errors As SslPolicyErrors) (certificate.Subject.Contains("CN=MyTrustedCompany.com")) 

的代碼沒問題 - >完美的作品100%。

問題是,它太深遠了。我認爲它的範圍就只能是我decalred它的方法中,但顯然這是「ServicePointManager」對象上的共享屬性,然後要堅持爲整個應用程序,這是我不想要的。

問題是後來我打電話給我的web服務等,並得到「無法建立信任關係...」異常。這是因爲在上面的代碼行中,我檢查了SSL證書specefic的主機名。我趕緊從測試回調返回「真」,因此所有的證書將被信任,而不是檢查一個specefic名稱(即MyTrustedCompany)和subsiquent請求工作。這就是我知道這個回調分配到達父親的方法。當然,我可以擴展回調包括所有其他certitificate的名字,但我會做的是設置了「ServerCertificateValidationCallback」回其默認行爲。像以下僞代碼:

ServicePointManager.ServerCertificateValidationCallback = Nothing 'Default checking behavior 

如何刪除自定義驗證並將其設置恢復爲其默認行爲?謝謝!

+0

您可以將其設置爲等同於執行默認行爲的函數:未使用自定義驗證時,會將證書名稱與用於創建請求的主機名進行比較。例如,如果Create(String)傳遞了「https://www.contoso.com/default.hmtl」參數,則默認行爲是客戶端根據www.contoso.com檢查證書。 http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx – Prescott 2010-11-11 22:25:50

回答

13

這實際上似乎工作(儘可能簡單),並使對象的行爲以其默認的方式。

ServicePointManager.ServerCertificateValidationCallback = Nothing 
+9

你有沒有想過是否有任何方法使這個線程安全?由於這個東西是靜態的,我會假設,每個使用Web服務的線程都會在設置時調用你的委託。 – galets 2011-09-13 22:36:44

+0

(意識到這是非常古老的......)你確定這有用嗎?在C#中設置爲null [據報道會通過一切](http://stackoverflow.com/a/8722292/1028230)。 – ruffin 2015-01-17 21:21:09

+0

是的,它的確行得通,將行爲設置恢復到默認狀態,因爲它會開始歧視SSL證書,並且不允許所有事情都通過。這是指定的回調方法,它具有「返回true」的功能,這是所有事情都可以通過的。 – atconway 2015-01-19 15:30:30

4

你要只對特定的網址返回true, 但除此之外,這個你想要做什麼,讓使用多代表的可能性。對於每個回調的邏輯可以包括經由反射的檢查,使得從某些組件調用時,由此產生一種特定的URL和某些應用之間隧道的回調僅返回true。

一種方法使用此代碼: 1.在你的對象的生命 2.設置包含「的BeSecure」代碼真正 3.發送HTTP請求的屬性早定義mIgnoreBadCertificates委託。 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

的一個關鍵點,以解決你的問題是事實,sender參數爲RemoteCertificateValidationCallbackWebRequest。您可以根據您的網絡請求檢查發件人,以便您只檢查您的網絡請求。這是我的(未經驗證的)解決方案:

// 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; 
     } 
    } 
} 
1
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"); 
    } 
} 

,在我的Program.cs命令行測試:

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

它可以做更多的證書和發送參數,但OP要求以上。

+2

確切地說,上面的解決方案引入了一個嚴重的安全問題,條件應該是:return(sslPolicyErrors == SslPolicyErrors.None)&& certificate.Subject.Contains(「CN = MyTrustedCompany.com」); – too 2015-03-18 12:46:29