Jak zignorować sprawdzanie certyfikatu, gdy ssl


137

Próbuję znaleźć sposób na zignorowanie sprawdzania certyfikatu, gdy żądam zasobu HTTPS, do tej pory znalazłem pomocny artykuł w Internecie.

Ale wciąż mam problem. Proszę przejrzeć mój kod. Po prostu nie rozumiem, co oznacza kod ServicePointManager.ServerCertificateValidationCallback.

Kiedy zostanie wywołana ta metoda delegata? I jeszcze jedno pytanie, w którym miejscu mam napisać ten kod? Przed ServicePointManager.ServerCertificateValidationCallbackwykonaniem czy przed 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;
    }
}   

Odpowiedzi:


69

Ponieważ istnieje tylko jeden globalny ServicePointManager , ustawienie ServicePointManager.ServerCertificateValidationCallback spowoduje, że wszystkie kolejne żądania odziedziczą tę zasadę. Ponieważ jest to globalne „ustawienie”, preferowane byłoby ustawienie go w metodzie Application_Start w Global.asax .

Ustawienie wywołania zwrotnego przesłania domyślne zachowanie i możesz samodzielnie utworzyć niestandardową procedurę sprawdzania poprawności.


A co z klientem, który nie ma Global.asax? Dzwonię do usługi REST działającej w sieci lokalnej z urządzenia przenośnego.
B. Clay Shannon

3
Pytanie jest specyficzne dla HttpWebRequest. Jeśli używasz innych środków, musisz zajrzeć do dokumentacji, jak to zrobić.
Sani Singh Huttunen

Używam WebRequest, który jest rzutowany na HttpWebRequest, na przykład: ((HttpWebRequest) żądanie) .Accept = contentType;
B. Clay Shannon

Jak stwierdziłem w mojej odpowiedzi: PREFEROWANE jest ustawienie tego w Global.asax, a nie wymaganie. Możesz to ustawić nawet przed wywołaniem usługi REST.
Sani Singh Huttunen

3
Zobacz ten link, aby znaleźć możliwe rozwiązanie.
Sani Singh Huttunen

180

Dla wszystkich zainteresowanych zastosowaniem tego rozwiązania na żądanie, jest to opcja i używa wyrażenia Lambda. To samo wyrażenie lambda można zastosować również do filtru globalnego, o którym wspomina blak3r. Wydaje się, że ta metoda wymaga platformy .NET 4.5.

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

W .NET 4.0 wyrażenie Lambda można zastosować do filtru globalnego jako takiego

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

2
Czy istnieje rozwiązanie na żądanie dla FtpWebRequest?
Timo

Wydaje się, że istnieje dobrze w moim 4.0
Nacht

Myślę, że jest to zdecydowanie lepsze rozwiązanie dla wariantu „globalnego”, chociaż oczywiście rozumiem, dlaczego chciałbyś go mieć. Osobiście wolę fabrykę żądań, która następnie zarządza tym wywołaniem zwrotnym walidacji. Dzięki Adam, fajne rozwiązanie.
Senator

2
Powrót truejest czymś, co możesz zrobić podczas eksperymentowania podczas programowania, jednak jest to niebezpieczne. Powinien być warunkowy.
Fred

1
Używanie (HttpWebRequest)WebRequest.Create(url)jest całkowicie poprawne, ale na moim pudełku HttpWebRequest.Create(url)nadal istnieje w projekcie przeznaczonym dla .Net 4.6.2. Wybór szefa kuchni, ale w tym momencie HttpClientjest prawdopodobnie lepszym API do użycia.
Adam Venezia

56

To zadziałało dla mnie:

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

Fragment stąd: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors


17
ServicePointManager.ServerCertificateValidationCallback + = (nadawca, certyfikat, łańcuch, sslPolicyErrors) => true;
David Rutgos

3
Zawsze zwracanie prawdy jest niepewne. Powinien warunkowo zwrócić prawdę.
Fred

Jest to przypadek na proces, więc nie jest to bezpieczne.
Michaił Orłow

27

Istnieje również krótkie rozwiązanie delegata:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 

3
Zawsze powrót truejest niepewny.
Fred

7
Tak, zawsze ufanie wszystkim certyfikatom SSL jest z definicji niebezpieczne. Unikaj tego, jeśli to możliwe.
Andrej Rommel

@AndrejRommel jaki jest twój sposób polecania?
Kiquenet

2
Zalecanym sposobem jest utworzenie ważnego certyfikatu SSL i właściwe wykorzystanie go, jeśli masz kontrolę nad serwerem. Skończyło się na utworzeniu takiego za pomocą letsencrypt.org.
Andrej Rommel,

6

Nawiasem mówiąc, jest to najmniej rozwlekły sposób na wyłączenie całej weryfikacji certyfikatu w danej aplikacji, o którym wiem:

ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;

5

Wspomniano, że przed .NET 4.5 właściwość na żądanie dostępu do niej ServicePointManagernie była dostępna.

Oto kod .NET 4.0, który zapewni dostęp do programu ServicePointna żądanie. Nie daje dostępu do wywołania zwrotnego na żądanie, ale powinien pozwolić ci dowiedzieć się więcej szczegółów o problemie. Po prostu uzyskaj dostęp do scvPoint.Certificate(lub ClientCertificatejeśli wolisz) właściwości.

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

Zgoda! Ale z drugiej strony, ten PO jest o tym, jak ignoreim, a nie im ufać.
Jesse Chisholm

W każdym razie, używając ServicePointNie zawsze mogę ufać wszystkim certyfikatom SSL, ani ignorować wszystkich certyfikatów , ponieważ nie ServerCertificateValidationCallback delegowałem w ServicePoint
Kiquenet

5

Zamiast dodawać wywołanie zwrotne do ServicePointManager, które globalnie przesłoni weryfikację certyfikatu, możesz ustawić wywołanie zwrotne w lokalnym wystąpieniu HttpClient. To podejście powinno wpływać tylko na wywołania wykonane przy użyciu tego wystąpienia HttpClient.

Oto przykładowy kod pokazujący, jak ignorowanie błędów weryfikacji certyfikatu dla określonych serwerów może zostać zaimplementowane w kontrolerze interfejsu API sieci Web.

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

}

Czy to nie zadziała tylko w przypadku platformy .NET Core? (Lub kiedykolwiek ServerCertificateCustomValidationCallback został dodany do HttpClientHandler)?
phillyslick

To rozwiązanie powinno działać w .Net Framework 4.5 i nowszych oraz .Net Core (chociaż nie testowałem tego w .Net Core).
Sheldon

@Sheldon, to był klejnot :) Używany z powodzeniem w moich wywołaniach api hosta lokalnego między aplikacjami .net i .net core. Niezłe obejście bez akceptowania wszystkich.
Duży

5

Dla .net core

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

3

Na podstawie odpowiedzi Adama i komentarza Roba użyłem tego:

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

który nieco filtruje „ignorowanie”. W razie potrzeby można oczywiście dodać innych emitentów. Zostało to przetestowane w .NET 2.0, ponieważ potrzebujemy obsługiwać starszy kod.


@karank Przepraszamy za spóźnioną odpowiedź - można ją dodać w dowolnym miejscu przed faktycznym wezwaniem, np. przed wywołaniem request.GetResponse (). Pamiętaj jednak, że wystawca może zawierać w Twoim przypadku coś innego.
Andrej Grobler

3

CA5386: Narzędzia do analizy luk ostrzegają o tych kodach.

Prawidłowy kod:

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

2

Wyraźnie wyrażone ...

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

2

Wersja Unity C # tego rozwiązania:

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

Głosuj za tym, ponieważ Unity rzuca na dowolny get lub zestaw handlerów.ServerCertificateCustomValidationCallback
Alexey Podlasov

0

Dodając do odpowiedzi Sani i blak3r, dodałem do kodu startowego mojej aplikacji, ale w VB:

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

Wydaje się, że to załatwia sprawę.


0

Wskazówka: możesz również użyć tej metody do śledzenia certyfikatów, które wkrótce wygasną. Może to uratować twój bekon, jeśli odkryjesz certyfikat, który wkrótce wygaśnie i możesz go naprawić na czas. Dobre również dla firm zewnętrznych - dla nas to DHL / FedEx. DHL właśnie pozwolił wygasnąć certyfikatowi, co szkodzi nam 3 dni przed Świętem Dziękczynienia. Na szczęście jestem w pobliżu, aby to naprawić ... tym razem!

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

Upewnij się, że poradzisz sobie z sytuacją, w której twój mechanizm ostrzegawczy może mieć wygasły certyfikat - w przeciwnym razie skończysz z przepełnieniem stosu!
Simon_Weaver,

Co to jest ProwlUtil.StepReached?
Kiquenet

Przepraszam, to tylko moja własna metoda wywoływania API Prowl, które może wysyłać powiadomienia na mój telefon. Jednak chcesz to zarejestrować, to dobrze. Lubię, gdy mój telefon jest podsłuchiwany na takie rzeczy!
Simon_Weaver

0

Kilka odpowiedzi powyżej działa. Zależało mi na podejściu, dzięki któremu nie musiałem ciągle wprowadzać zmian w kodzie i nie powodowałoby, że kod byłby niezabezpieczony. Dlatego stworzyłem białą listę. Biała lista może być utrzymywana w dowolnym magazynie danych. Użyłem pliku konfiguracyjnego, ponieważ jest to bardzo mała lista.

Mój kod jest poniżej.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, error) => {
    return error == System.Net.Security.SslPolicyErrors.None || certificateWhitelist.Contains(cert.GetCertHashString());
};
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.