Как установить свойство ServerCertificateValidationCallback обратно к его поведению по умолчанию? - PullRequest
16 голосов
/ 11 ноября 2010

Я использую следующую строку кода в одном методе, чтобы явно проверить и доверять 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%.

Проблема в том, что это слишком далеко.Я думал, что его область действия будет только в пределах метода, который я его декальцировал, но, очевидно, это свойство Shared объекта 'ServicePointManager', которое затем должно сохраняться для всего приложения, которое мне не нужно.

позже я звоню в мои веб-службы и т. д. и получаю исключение "Не удалось установить доверительные отношения ...".Это потому, что в строке кода выше я проверяю имя хоста SSL-сертификата, специально предназначенного для этого метода.Я быстро протестировал возвращение 'True' из обратного вызова, чтобы все сертификаты были доверенными, вместо того, чтобы проверять конкретное имя (т.е. MyTrustedCompany) и последующие запросы работали .Вот как я знаю, что это назначение обратного вызова достигает отца, чем этот единственный метод.Конечно, я мог бы расширить обратный вызов, включив в него все другие сертифицирующие имена, но я бы , а не , сделал бы, чтобы 'ServerCertificateValidationCallback' вернулся к его поведению по умолчанию.Как и в приведенном ниже псевдокоде:

ServicePointManager.ServerCertificateValidationCallback = Nothing  'Default checking behavior

Как удалить пользовательскую проверку и вернуть ее к поведению по умолчанию?Спасибо!

Ответы [ 4 ]

13 голосов
/ 18 ноября 2010

На самом деле это работает (так просто), что заставляет объект вести себя по умолчанию.

ServicePointManager.ServerCertificateValidationCallback = Nothing
4 голосов
/ 02 августа 2013

Ключевым моментом для решения вашей проблемы является тот факт, что параметр sender для RemoteCertificateValidationCallback является 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 голосов
/ 23 июля 2011

Вы захотите возвращать true только для определенных URL-адресов, но в противном случае это будет делать то, что вы хотите, оставляя возможность использования нескольких делегатов.Логика для каждого обратного вызова может включать проверку через отражение, так что обратный вызов возвращает 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");
    }
1 голос
/ 28 октября 2014
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");

Можно сделать больше с параметрами сертификата и отправителя, но ОП запросил выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...