Як ігнорувати перевірку сертифіката, коли ssl


132

Я намагаюся знайти спосіб ігнорувати перевірку сертифіката при запиті ресурсу 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;
    }
}   

Відповіді:


67

Оскільки існує лише один глобальний ServicePointManager , встановлення ServicePointManager.ServerCertificateValidationCallback призведе до того, що всі наступні запити будуть успадковані цією політикою. Оскільки це глобальне "налаштування", бажано встановити його методом Application_Start в Global.asax .

Встановлення зворотного дзвінка замінює поведінку за замовчуванням, і ви можете самостійно створити користувацьку процедуру перевірки.


Що з клієнтом, який не має Global.asax? Я дзвоню службу REST, що працює в локальній мережі з портативного пристрою.
Б. Клей Шеннон

3
Питання специфічне для HttpWebRequest. Якщо ви використовуєте будь-які інші засоби, вам доведеться подивитися в документації, як це досягти.
Сані Сінгх Хуттунен

Я використовую WebRequest, який передається на HttpWebRequest, наприклад: ((HttpWebRequest) запит) .Accept = contentType;
Б. Клей Шеннон

Як зазначено у моїй відповіді: ВИКОРИСТОВАНО встановлювати його в Global.asax не є вимогою. Ви навіть можете встановити його перед викликом до служби REST.
Сані Сінгх Хуттунен

3
Дивіться це посилання для можливого рішення.
Сані Сінгх Хуттунен

174

Для всіх, хто зацікавлений у застосуванні цього рішення на основі запиту, це варіант і використовує вираз Lambda. Той самий вираз лямбда може бути застосований і до глобального фільтра, згаданого 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 Lambda Expression можна застосувати до глобального фільтра як такого

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

2
Чи є якесь рішення на запит для FtpWebRequest?
Тимо

Здається, існує добре в моєму 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


17
ServicePointManager.ServerCertificateValidationCallback + = (відправник, сертифікат, ланцюг, sslPolicyErrors) => вірно;
Девід Рутгос

3
Завжди повертати справжню небезпечно. Це повинно умовно повернути істину.
Фред

Це за один процес, тому це не є безпечним.
Михайло Орлов

25

Також є рішення про короткий делегат:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 

3
Завжди повертатися trueнебезпечно.
Фред

7
Так, завжди довіряти всім SSL-сертифікатам небезпечно. Уникайте, якщо це можливо.
Андрій Роммель

@AndrejRommel, що ти рекомендуєш?
Кікенет

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.

Ось зразок коду, який показує, як ігнорування помилок перевірки сертифіката для конкретних серверів може бути реалізовано в контролері Web 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-дзвінки між .net та .net core додаток з успіхом. Гарний спосіб вирішення, не приймаючи всіх.
Великий

3

На основі відповіді Адама та коментаря Роба я використав це:

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

що дещо фільтрує "ігнорування". Інші емітенти можуть бути додані, як вимагається звичайно. Це було перевірено в .NET 2.0, оскільки нам потрібно підтримати деякий застарілий код.


@karank Вибачте за пізню відповідь - її можна додати будь-де перед фактичним викликом, наприклад. перед викликом запиту.GetResponse (). Зауважте, що Емітент може містити щось інше у вашому випадку.
Андрій Гроблер

3

CA5386: Інструменти аналізу вразливості попереджають вас про ці коди.

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

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
{
   return (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != SslPolicyErrors.RemoteCertificateNotAvailable;
};

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;
}

0

Додаючи відповіді Sani та blak3r, до стартового коду моєї програми я додав наступне, але в VB:

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

Здається, зробити трюк.


0

Порада: Ви також можете скористатися цим методом для відстеження сертифікатів, які термін дії закінчується незабаром. Це може врятувати ваш бекон, якщо ви виявите cert, який скоро закінчиться, і зможете його виправити вчасно. Добре також для сторонніх компаній - для нас це 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

Що таке ProwlUtil.StepReached?
Кікенет

Вибачте, це лише мій власний метод для виклику API Prowl, який може надсилати сповіщення на мій телефон. Однак ви хочете ввійти, це добре. Мені подобається, що мене записують на телефон за такі речі!
Simon_Weaver

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.