Come ignorare il controllo del certificato quando ssl


132

Sto cercando di trovare un modo per ignorare il controllo del certificato quando richiedo una risorsa Https, finora ho trovato un articolo utile in Internet.

Ma ho ancora qualche problema. Si prega di rivedere il mio codice. Non capisco cosa significhi il codice ServicePointManager.ServerCertificateValidationCallback.

Quando verrà chiamato questo metodo delegato? E un'altra domanda, in quale posto dovrei scrivere questo codice? Prima di ServicePointManager.ServerCertificateValidationCallbackeseguire o prima 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;
    }
}   

Risposte:


67

Poiché esiste un solo ServicePointManager globale , l'impostazione di ServicePointManager.ServerCertificateValidationCallback produrrà il risultato che tutte le richieste successive erediteranno questo criterio. Poiché si tratta di una "impostazione" globale, sarebbe preferibile impostarla nel metodo Application_Start in Global.asax .

L'impostazione del callback ha la precedenza sul comportamento predefinito e puoi creare tu stesso una routine di convalida personalizzata.


Che dire di un client che non ha Global.asax? Sto chiamando un servizio REST in esecuzione sulla rete locale da un dispositivo portatile.
B. Clay Shannon,

3
La domanda è specifica HttpWebRequest. Se stai usando altri mezzi, dovrai consultare la documentazione per ottenere questo risultato.
Sani Singh Huttunen,

Sto usando WebRequest, che viene trasmesso a HttpWebRequest, come ad esempio: ((HttpWebRequest) request) .Accept = contentType;
B. Clay Shannon,

Come indicato nella mia risposta: è PREFERITO impostare in Global.asax non un requisito. È anche possibile impostarlo prima della chiamata al servizio REST.
Sani Singh Huttunen,

3
Vedi questo link per una possibile soluzione.
Sani Singh Huttunen,

174

Per chiunque sia interessato ad applicare questa soluzione in base alla richiesta, questa è un'opzione e utilizza un'espressione Lambda. La stessa espressione Lambda può essere applicata anche al filtro globale citato da blak3r. Questo metodo sembra richiedere .NET 4.5.

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

In .NET 4.0, l'espressione Lambda può essere applicata al filtro globale in quanto tale

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

2
Esiste una soluzione per richiesta per FtpWebRequest?
Timo,

Sembra esistere nel mio 4.0
Nacht il

Penso che sia di gran lunga una soluzione migliore per la variante "globale", anche se ovviamente posso capire perché lo vorresti. Personalmente preferisco una factory di richiesta che quindi gestisce questo callback di validazione. Grazie Adam, bella soluzione.
Il senatore

2
Il ritorno trueè qualcosa che puoi fare durante la sperimentazione durante lo sviluppo, tuttavia non è sicuro. Dovrebbe essere un condizionale.
Fred,

1
L'utilizzo (HttpWebRequest)WebRequest.Create(url)è perfettamente valido, ma sulla mia scatola HttpWebRequest.Create(url)esiste ancora in un progetto destinato. Net 4.6.2. La scelta dello chef, ma a questo punto HttpClientè probabilmente l'API migliore da usare.
Adam Venezia,

53

Questo ha funzionato per me:

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

Snippet da qui: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors


17
ServicePointManager.ServerCertificateValidationCallback + = (mittente, certificato, catena, sslPolicyErrors) => true;
David Rutgos,

3
Restituire sempre vero è insicuro. Dovrebbe restituire condizionalmente vero.
Fred,

Questo è per processo, quindi non è sicuro.
Mikhail Orlov,

25

Inoltre c'è la soluzione per delegati brevi:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 

3
Il ritorno trueè sempre insicuro.
Fred,

7
Sì, fidarsi sempre di tutti i certificati SSL non è sicuro per definizione. Evita di farlo se possibile.
Andrej Rommel,

@AndrejRommel qual è la tua strada consigliata?
Kiquenet,

2
Il modo consigliato è creare un certificato SSL valido e utilizzarlo correttamente se si ha il controllo sul server. Abbiamo finito per crearne uno usando letsencrypt.org.
Andrej Rommel,

5

È stato menzionato che prima di .NET 4.5 la proprietà sulla richiesta di accesso ServicePointManagernon era disponibile.

Ecco il codice .NET 4.0 che ti darà accesso ServicePointsu base per richiesta. Non ti dà accesso al callback per richiesta, ma dovrebbe permetterti di scoprire maggiori dettagli sul problema. Accedi alle proprietà scvPoint.Certificate(o ClientCertificatese preferisci).

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

Concordato! Ma poi, questo PO riguarda come ignorefarli, non fidarsi di loro.
Jesse Chisholm l'

Comunque, usando ServicePointI non posso sempre fidarmi di tutti i certificati SSL, né ignorare tutti i certificati , perché non ha ServerCertificateValidationCallback delegato in ServicePoint
Kiquenet

4

Per inciso, questo è il modo meno dettagliato per disattivare tutta la convalida del certificato in una determinata app che conosco:

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

4

Anziché aggiungere un callback a ServicePointManager che sostituirà la convalida del certificato a livello globale, è possibile impostare il callback su un'istanza locale di HttpClient. Questo approccio dovrebbe influire solo sulle chiamate effettuate utilizzando quell'istanza di HttpClient.

Ecco un codice di esempio che mostra come ignorare gli errori di convalida dei certificati per server specifici potrebbe essere implementato in un controller API 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;
    }

}

Non funzionerà solo con .NET Core? (O ogni volta che ServerCertificateCustomValidationCallback è stato aggiunto a HttpClientHandler)?
Phillyslick,

Questa soluzione dovrebbe funzionare in .Net Framework 4.5 e versioni successive e .Net Core (anche se non l'ho testato in .Net Core).
Sheldon,

@Sheldon, questo è stato un vero gioiello :) Utilizzato con successo nel mio localhost api-call tra un'app .net e un'app core .net con successo. Bella soluzione alternativa senza accettare tutto.
Grande

3

Sulla base della risposta di Adam e del commento di Rob, ho usato questo:

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

che filtra un po '"ignorando". Altri emittenti possono essere aggiunti, se necessario, ovviamente. Questo è stato testato in .NET 2.0 in quanto dobbiamo supportare del codice legacy.


@karank Ci scusiamo per la risposta tardiva - Può essere aggiunto ovunque prima della chiamata effettiva, ad es. prima di chiamare request.GetResponse (). Si noti che l'Emittente potrebbe contenere qualcos'altro nel tuo caso.
Andrej Grobler,

3

CA5386: Gli strumenti di analisi della vulnerabilità ti avviseranno di questi codici.

Codice corretto:

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

3

Per core .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

Espresso esplicitamente ...

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

Aggiungendo alle risposte di Sani e blak3r, ho aggiunto quanto segue al codice di avvio per la mia applicazione, ma in VB:

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

Sembra fare il trucco.


0

Suggerimento: è inoltre possibile utilizzare questo metodo per tenere traccia dei certificati che dovrebbero scadere presto. Questo può salvare la tua pancetta se scopri un certificato che sta per scadere e puoi farlo riparare in tempo. Buono anche per aziende di terze parti: per noi questo è DHL / FedEx. DHL ha appena lasciato scadere un certificato che ci sta rovinando 3 giorni prima del Ringraziamento. Fortunatamente sono in giro per ripararlo ... questa volta!

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

Assicurati di gestire la situazione in cui il tuo meccanismo di avviso può avere un certificato scaduto - o finirai con uno stackoverflow!
Simon_Weaver,

Che cosa è ProwlUtil.StepReached?
Kiquenet,

Mi dispiace che è solo il mio metodo per chiamare l'API Prowl che può inviare notifiche al mio telefono. Comunque tu voglia registrarlo è buono. Mi piace essere infastidito sul mio telefono per cose come questa!
Simon_Weaver

0

Diverse risposte sopra il lavoro. Volevo un approccio che non dovevo continuare a apportare modifiche al codice e non rendevo il mio codice insicuro. Quindi ho creato una lista bianca. La whitelist può essere gestita in qualsiasi archivio dati. Ho usato il file di configurazione poiché è un elenco molto piccolo.

Il mio codice è sotto.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, error) => {
    return error == System.Net.Security.SslPolicyErrors.None || certificateWhitelist.Contains(cert.GetCertHashString());
};

0

Unity C # Versione di questa soluzione:

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.