2010-11-11 36 views
16

tôi sử dụng dòng mã sau đây trong vòng một phương pháp duy nhất để kiểm tra một cách rõ ràng và tin tưởng một cert SSL từ các máy chủ sau: MyTrustedCompany.com:Làm cách nào để đặt thuộc tính 'ServerCertificateValidationCallback' về hành vi mặc định của nó?

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

Không có vấn đề với mã -> hoạt động hoàn hảo 100%.

Vấn đề là, nó quá xa. Tôi nghĩ phạm vi của nó sẽ chỉ nằm trong phương pháp mà tôi đã vẽ nó, nhưng dường như nó là một thuộc tính được chia sẻ trên đối tượng 'ServicePointManager', và sau đó phải tồn tại cho toàn bộ ứng dụng mà tôi không muốn.

Vấn đề là sau này tôi đang gọi dịch vụ web của tôi, v.v. và nhận được ngoại lệ "Không thể thiết lập mối quan hệ tin cậy ...". Điều này là do trong dòng mã ở trên, tôi kiểm tra tên máy chủ của một đặc tả SSL cert cho phương thức đó. Tôi đã nhanh chóng kiểm tra Trả lại 'Đúng' từ cuộc gọi lại để tất cả các chứng chỉ sẽ được tin cậy thay vì kiểm tra tên cụ thể (ví dụ: MyTrustedCompany) và các yêu cầu cấp phép đã hoạt động. Đây là cách tôi biết nhiệm vụ gọi lại này đến với cha hơn là phương pháp duy nhất. Chắc chắn tôi có thể mở rộng gọi lại để bao gồm tất cả các tên chứng chỉ khác, nhưng những gì tôi sẽ thay vì làm là đặt 'ServerCertificateValidationCallback' về hành vi mặc định của nó. Giống như mã giả bên dưới:

ServicePointManager.ServerCertificateValidationCallback = Nothing 'Default checking behavior 

Làm cách nào để xóa xác thực tùy chỉnh và đặt lại hành vi mặc định? Cảm ơn!

+0

Bạn có thể đặt bằng chức năng hành vi mặc định là: Khi xác thực tùy chỉnh không được sử dụng, tên chứng chỉ được so sánh với tên máy chủ được sử dụng để tạo yêu cầu. Ví dụ: nếu Tạo (Chuỗi) được chuyển một tham số của "https://www.contoso.com/default.hmtl", hành vi mặc định là dành cho ứng dụng khách để kiểm tra chứng chỉ với www.contoso.com. http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx – Prescott

Trả lời

13

Điều này thực sự dường như hoạt động (đơn giản như hiện tại) và làm cho đối tượng hoạt động theo cách mặc định.

ServicePointManager.ServerCertificateValidationCallback = Nothing 
+9

Bạn đã tìm ra liệu có cách nào để làm cho luồng này an toàn không? Kể từ khi điều này là tĩnh, tôi sẽ giả định, mỗi thread sử dụng dịch vụ web sẽ gọi đại biểu của bạn trong khi nó được thiết lập. – galets

+0

(Nhận ra điều này thực sự cũ ...) Bạn có chắc chắn rằng các công trình? Thiết lập để null trong C# [báo cáo sẽ gửi tất cả mọi thứ thông qua] (http://stackoverflow.com/a/8722292/1028230). – ruffin

+0

Có nó đã làm việc thiết lập các hành vi trở lại mặc định của nó ở chỗ nó sau đó sẽ bắt đầu phân biệt đối xử với chứng chỉ SSL và _not_ cho phép tất cả mọi thứ thông qua. Đó là phương thức gọi lại được chỉ định có chức năng 'trả về true' là thứ cho phép mọi thứ qua. – atconway

4

Bạn sẽ muốn chỉ trở về đúng với URL nhất định, nhưng mặt khác, điều này làm những gì bạn muốn, để lại khả năng sử dụng nhiều đại biểu. Logic cho mỗi callback có thể bao gồm một kiểm tra thông qua sự phản chiếu để callback chỉ trả về true khi được gọi từ các thành phần nhất định, do đó tạo ra một loại đường hầm giữa các URL nhất định và các ứng dụng nhất định.

Một cách để sử dụng mã này: 1. Xác định mIgnoreBadCertificates đại biểu đầu trong cuộc sống của đối tượng của bạn 2. Thiết lập thuộc tính chứa mã 'beSecure' true 3. Gửi yêu cầu HTTP. 4. Đặt thuộc tính sai. Điều này rất quan trọng và cần được thực hiện theo cách đảm bảo nó được gọi. Mẫu IDisposable là một tùy chọn.

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

Một điểm mấu chốt để giải quyết vấn đề của bạn là một thực tế rằng sender tham số cho RemoteCertificateValidationCallbackWebRequest. Bạn có thể kiểm tra người gửi dựa trên yêu cầu web của bạn để bạn chỉ thực hiện việc kiểm tra yêu cầu web của mình. Đây là của tôi (tương đối chưa được kiểm tra) giải pháp:

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

và trong program.cs tôi commandline kiểm tra:

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

Có thể làm nhiều hơn với các thông số giấy chứng nhận và người gửi nhưng OP yêu cầu ở trên.

+2

Để chính xác giải pháp trên đưa ra một vấn đề bảo mật nghiêm trọng, điều kiện phải là: return (sslPolicyErrors == SslPolicyErrors.None) && certificate.Subject.Contains ("CN = MyTrustedCompany.com"); – too

Các vấn đề liên quan