Как игнорировать проверку сертификата при ssl

133

Я пытаюсь найти способ игнорировать проверку сертификата при запросе ресурса Https, но пока я нашел полезную статью в Интернете.

Но у меня все еще есть проблема. Пожалуйста, просмотрите мой код. Я просто не понимаю, что означает код ServicePointManager.ServerCertificateValidationCallback.

Когда будет вызван этот метод делегата? И еще вопрос, в каком месте писать этот код? До ServicePointManager.ServerCertificateValidationCallbackисполнения или раньше Stream stream = request.GetRequestStream()?

public HttpWebRequest GetRequest()
{
    CookieContainer cookieContainer = new CookieContainer();

    // Create a request to the server
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_remoteUrl);

    #region Set request parameters

    request.Method = _context.Request.HttpMethod;
    request.UserAgent = _context.Request.UserAgent;
    request.KeepAlive = true;
    request.CookieContainer = cookieContainer;
    request.PreAuthenticate = true;
    request.AllowAutoRedirect = false;

    #endregion

    // For POST, write the post data extracted from the incoming request
    if (request.Method == "POST")
    {
        Stream clientStream = _context.Request.InputStream;
        request.ContentType = _context.Request.ContentType;
        request.ContentLength = clientStream.Length;

        ServicePointManager.ServerCertificateValidationCallback = delegate(
            Object obj, X509Certificate certificate, X509Chain chain, 
            SslPolicyErrors errors)
            {
                return (true);
            };

            Stream stream = request.GetRequestStream();

            ....
        }

        ....

        return request;
    }
}   
Joe.wang
источник
Возможный дубликат ошибок сертификата C # Ignore?
Матиас

Ответы:

67

Поскольку существует только один глобальный ServicePointManager , установка ServicePointManager.ServerCertificateValidationCallback приведет к тому, что все последующие запросы будут наследовать эту политику. Поскольку это глобальная «настройка», было бы предпочтительнее установить ее в методе Application_Start в Global.asax .

Установка обратного вызова переопределяет поведение по умолчанию, и вы можете сами создать собственную процедуру проверки.

Сани Сингх Хуттунен
источник
А как насчет клиента, у которого нет Global.asax? Я вызываю службу REST, работающую в локальной сети, с портативного устройства.
Б. Клэй Шеннон
3
Вопрос специфический для HttpWebRequest. Если вы используете какие-либо другие средства, вам нужно будет посмотреть в документации, как это сделать.
Сани Сингх Хуттунен
Я использую WebRequest, который преобразуется в HttpWebRequest, например: ((HttpWebRequest) request) .Accept = contentType;
Б. Клей Шеннон
Как указано в моем ответе: ПРЕДПОЧТИТЕЛЬНО устанавливать его в Global.asax, а не в обязательном порядке. Вы даже можете установить его перед вызовом службы REST.
Сани Сингх Хуттунен
3
См. Эту ссылку для возможного решения.
Сани Сингх Хуттунен
175

Для всех, кто заинтересован в применении этого решения для каждого запроса, это вариант, использующий лямбда-выражение. То же лямбда-выражение можно применить и к глобальному фильтру, упомянутому blak3r. Похоже, для этого метода требуется .NET 4.5.

String url = "https://www.stackoverflow.com";
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

В .NET 4.0 лямбда-выражение может применяться к глобальному фильтру как таковому.

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
Адам Венеция
источник
2
Есть ли какое-либо решение для FtpWebRequest по запросу?
Timo
Кажется, в моей 4.0 все нормально
ночь,
Я думаю, что это намного более хорошее решение для «глобального» варианта, хотя, конечно, я могу понять, зачем вам это нужно. Лично я предпочитаю фабрику запросов, которая затем управляет этим обратным вызовом проверки. Спасибо, Адам, хорошее решение.
Сенатор
2
Возврат true- это то, что вы можете сделать, экспериментируя во время разработки, но это небезопасно. Это должно быть условно.
Фред
1
Использование (HttpWebRequest)WebRequest.Create(url)вполне допустимо, но в моем случае HttpWebRequest.Create(url)все еще существует в проекте, ориентированном на .Net 4.6.2. Выбор шеф-повара, но на данный момент HttpClientэто, вероятно, лучший API для использования.
Адам Венеция
53

Это сработало для меня:

System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                        System.Security.Cryptography.X509Certificates.X509Chain chain,
                        System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        return true; // **** Always accept
    };

Фрагмент отсюда: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors

blak3r
источник
17
ServicePointManager.ServerCertificateValidationCallback + = (отправитель, сертификат, цепочка, sslPolicyErrors) => true;
Дэвид Рутгос
3
Всегда возвращать истину небезопасно. Он должен условно возвращать истину.
Фред
Это отдельный процесс, поэтому это небезопасно.
Михаил Орлов
25

Также есть решение для короткого делегата:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 
Андрей Роммель
источник
3
Всегда возвращаться trueнебезопасно.
Фред
7
Да, всегда доверять всем SSL-сертификатам небезопасно по определению. По возможности избегайте этого.
Андрей Роммель
@AndrejRommel, что вы рекомендуете?
Kiquenet 06
2
Рекомендуемый способ - создать действующий сертификат SSL и правильно его использовать, если вы контролируете сервер. В итоге мы создали его с помощью letsencrypt.org.
Андрей Роммель
5

Было упомянуто, что до .NET 4.5 свойство в запросе на доступ к нему ServicePointManagerбыло недоступно.

Вот код .NET 4.0, который предоставит вам доступ для ServicePointкаждого запроса. Он не дает вам доступа к обратному вызову для каждого запроса, но должен позволить вам узнать более подробную информацию о проблеме. Просто откройте scvPoint.Certificate(или, ClientCertificateесли хотите) свойства.

WebRequest request = WebRequest.Create(uri);

// oddity: these two .Address values are not necessarily the same!
//  The service point appears to be related to the .Host, not the Uri itself.
//  So, check the .Host vlaues before fussing in the debugger.
//
ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);
if (null != svcPoint)
{
    if (!request.RequestUri.Host.Equals(svcPoint.Address.Host, StringComparison.OrdinalIgnoreCase))
    {
        Debug.WriteLine(".Address              == " + request.RequestUri.ToString());
        Debug.WriteLine(".ServicePoint.Address == " + svcPoint.Address.ToString());
    }
    Debug.WriteLine(".IssuerName           == " + svcPoint.Certificate.GetIssuerName());
}
Джесси Чизхолм
источник
Согласовано! Но тогда этот ОП о том, как ignoreим, а не доверять им.
Джесси Чизхолм
В любом случае, используя, ServicePointя не могу всегда доверять всем SSL-сертификатам, а также игнорировать все сертификаты , потому что не ServerCertificateValidationCallback делегировал в ServicePoint
Kiquenet
4

Кстати, это наименее подробный способ отключить всю проверку сертификатов в данном приложении, о котором я знаю:

ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
Кристиан Финдли
источник
4

Вместо того, чтобы добавлять обратный вызов в ServicePointManager, который переопределит проверку сертификата глобально, вы можете установить обратный вызов для локального экземпляра HttpClient. Этот подход должен влиять только на вызовы, сделанные с использованием этого экземпляра HttpClient.

Вот пример кода, показывающий, как игнорирование ошибок проверки сертификатов для конкретных серверов может быть реализовано в контроллере веб-API.

using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public class MyController : ApiController
{

    // use this HttpClient instance when making calls that need cert errors suppressed
    private static readonly HttpClient httpClient;

    static MyController()
    {
        // create a separate handler for use in this controller
        var handler = new HttpClientHandler();

        // add a custom certificate validation callback to the handler
        handler.ServerCertificateCustomValidationCallback = ((sender, cert, chain, errors) => ValidateCert(sender, cert, chain, errors));

        // create an HttpClient that will use the handler
        httpClient = new HttpClient(handler);
    }

    protected static ValidateCert(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
    {

        // set a list of servers for which cert validation errors will be ignored
        var overrideCerts = new string[]
        {
            "myproblemserver",
            "someotherserver",
            "localhost"
        };

        // if the server is in the override list, then ignore any validation errors
        var serverName = cert.Subject.ToLower();
        if (overrideCerts.Any(overrideName => serverName.Contains(overrideName))) return true;

        // otherwise use the standard validation results
        return errors == SslPolicyErrors.None;
    }

}
Шелдон
источник
Разве это не будет работать только для .NET Core? (Или всякий раз, когда ServerCertificateCustomValidationCallback был добавлен в HttpClientHandler)?
phillyslick
Это решение должно работать в .Net Framework 4.5 и более поздних версиях, а также в .Net Core (хотя я не тестировал его в .Net Core).
Шелдон
@Sheldon, это была жемчужина :) Успешно использовалась в моих api-вызовах localhost между приложениями .net и .net. Хороший обходной путь без принятия всего.
Большой
3

Основываясь на ответе Адама и комментарии Роба, я использовал это:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => certificate.Issuer == "CN=localhost";

который несколько фильтрует "игнорирование". Конечно, при необходимости могут быть добавлены другие эмитенты. Это было протестировано в .NET 2.0, поскольку нам необходимо поддерживать некоторый устаревший код.

Андрей Гроблер
источник
@karank Извините за поздний ответ - его можно добавить где угодно перед фактическим вызовом, например. перед вызовом request.GetResponse (). Обратите внимание, что Issuer может содержать что-то еще в вашем случае.
Андрей Гроблер
3

CA5386: инструменты анализа уязвимостей сообщат вам об этих кодах.

Правильный код:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
{
   return (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != SslPolicyErrors.RemoteCertificateNotAvailable;
};
dev_O
источник
3

Для ядра .net

using (var handler = new HttpClientHandler())
{ 
    // allow the bad certificate
    handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => true;
    using (var httpClient = new HttpClient(handler))
    {
        await httpClient.PostAsync("the_url", null);
    }
}
Рич Хильдебранд
источник
2

Выражено прямо ...

ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(CertCheck);

private static bool CertCheck(object sender, X509Certificate cert,
X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
    return true;
}
dev_O
источник
0

Добавляя к ответам Sani и blak3r, я добавил следующее в код запуска для своего приложения, но в VB:

'** Overriding the certificate validation check.
Net.ServicePointManager.ServerCertificateValidationCallback = Function(sender, certificate, chain, sslPolicyErrors) True

Кажется, добился цели.

MCattle
источник
0

Совет: вы также можете использовать этот метод для отслеживания сертификатов, срок действия которых скоро истечет. Это может спасти ваш бекон, если вы обнаружите сертификат, срок действия которого истекает, и сможете вовремя его исправить. Хорошо также и для сторонних компаний - для нас это DHL / FedEx. DHL просто допустила истечение срока действия сертификата, который нас облажает за 3 дня до Дня Благодарения. К счастью, я могу исправить это ... на этот раз!

    private static DateTime? _nextCertWarning;
    private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
    {
        if (error == SslPolicyErrors.None)
        {
            var cert2 = cert as X509Certificate2;
            if (cert2 != null)
            { 
                // If cert expires within 2 days send an alert every 2 hours
                if (cert2.NotAfter.AddDays(-2) < DateTime.Now)
                {
                    if (_nextCertWarning == null || _nextCertWarning < DateTime.Now)
                    {
                        _nextCertWarning = DateTime.Now.AddHours(2);

                        ProwlUtil.StepReached("CERT EXPIRING WITHIN 2 DAYS " + cert, cert.GetCertHashString());   // this is my own function
                    }
                }
            }

            return true;
        }
        else
        {
            switch (cert.GetCertHashString())
            {
                // Machine certs - SELF SIGNED
                case "066CF9CAD814DE2097D367F22D3A7E398B87C4D6":    

                    return true;

                default:
                    ProwlUtil.StepReached("UNTRUSTED CERT " + cert, cert.GetCertHashString());
                    return false;
            }
        }
    }
Simon_Weaver
источник
Убедитесь, что вы справились с ситуацией, когда ваш механизм оповещения может иметь истекший сертификат - или вы закончите с переполнением стека!
Simon_Weaver
Что есть ProwlUtil.StepReached?
Kiquenet 05
Извините, это просто мой собственный метод вызова Prowl API, который может отправлять уведомления на мой телефон. Как бы то ни было, вы хотите регистрировать это хорошо. Мне нравится, когда в моем телефоне прослушиваются подобные вещи!
Simon_Weaver 05
0

Несколько ответов выше работают. Мне нужен был подход, при котором мне не приходилось постоянно вносить изменения в код и который не делал мой код небезопасным. Поэтому я создал белый список. Белый список можно вести в любом хранилище данных. Я использовал файл конфигурации, так как это очень маленький список.

Мой код ниже.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, error) => {
    return error == System.Net.Security.SslPolicyErrors.None || certificateWhitelist.Contains(cert.GetCertHashString());
};
Оса Э
источник
0

Unity C # Версия этого решения:

void Awake()
{
    System.Net.ServicePointManager.ServerCertificateValidationCallback += ValidateCertification;
}

void OnDestroy()
{
    ServerCertificateValidationCallback = null;
}

public static bool ValidateCertification(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    return true;
}
Сантьяго Game Lover
источник