Cómo ignorar la verificación del certificado cuando ssl

132

Estoy tratando de encontrar una manera de ignorar la verificación del certificado cuando solicito un recurso Https, hasta ahora, encontré algún artículo útil en Internet.

Pero todavía tengo algún problema. Por favor revise mi código. Simplemente no entiendo qué significa el código ServicePointManager.ServerCertificateValidationCallback.

¿Cuándo se llamará a este método delegado? Y una pregunta más, ¿en qué lugar debo escribir este código? Antes de ServicePointManager.ServerCertificateValidationCallbackejecutar o antes 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
fuente
Posible duplicado de C # ¿Ignorar errores de certificado?
Matyas

Respuestas:

67

Como solo hay un ServicePointManager global , la configuración de ServicePointManager.ServerCertificateValidationCallback generará el resultado de que todas las solicitudes posteriores heredarán esta política. Dado que es una "configuración" global, se preferiría establecerla en el método Application_Start en Global.asax .

La configuración de la devolución de llamada anula el comportamiento predeterminado y usted mismo puede crear una rutina de validación personalizada.

Sani Singh Huttunen
fuente
¿Qué pasa con un cliente que no tiene Global.asax? Estoy llamando a un servicio REST que se ejecuta en la red local desde un dispositivo portátil.
B. Clay Shannon
3
La pregunta es específica de HttpWebRequest. Si está utilizando cualquier otro medio, tendrá que buscar en la documentación cómo lograr esto.
Sani Singh Huttunen
Estoy usando WebRequest, que se envía a HttpWebRequest, como por ejemplo: ((HttpWebRequest) request) .Accept = contentType;
B. Clay Shannon
Como se indica en mi respuesta: es PREFERIDO configurarlo en Global.asax, no es un requisito. Incluso puede configurarlo antes de la llamada al servicio REST.
Sani Singh Huttunen
3
Vea este enlace para una posible solución.
Sani Singh Huttunen
174

Para cualquier persona interesada en aplicar esta solución por solicitud, esta es una opción y utiliza una expresión Lambda. La misma expresión de Lambda se puede aplicar al filtro global mencionado por blak3r también. Este método parece requerir .NET 4.5.

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

En .NET 4.0, la expresión Lambda se puede aplicar al filtro global como tal

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
Adam Venezia
fuente
2
¿Hay alguna solución por solicitud para FtpWebRequest?
Timo
Parece existir bien en mi 4.0
Nacht
Creo que es, con mucho, una mejor solución para la variante 'global', aunque, por supuesto, puedo entender por qué la querrías. Personalmente, estoy a favor de una fábrica de solicitudes que luego gestiona esta devolución de llamada de validación. Gracias Adam, buena solución.
El senador
2
Regresar truees algo que puede hacer al experimentar durante el desarrollo, sin embargo, es inseguro. Debería ser un condicional.
Fred
1
El uso (HttpWebRequest)WebRequest.Create(url)es perfectamente válido, pero en mi caja, HttpWebRequest.Create(url)todavía existe en un proyecto dirigido a .Net 4.6.2. La elección del chef, pero en este punto HttpClientes probablemente la mejor API para usar.
Adam Venezia
53

Esto funcionó para mí:

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

Fragmento de aquí: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors

blak3r
fuente
17
ServicePointManager.ServerCertificateValidationCallback + = (remitente, certificado, cadena, sslPolicyErrors) => verdadero;
David Rutgos
3
Siempre volver verdadero es inseguro. Debería devolver condicionalmente verdadero.
Fred
Esto es por proceso, por lo que no es seguro.
Mikhail Orlov
25

También existe la solución delegada corta:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 
Andrej Rommel
fuente
3
Siempre regresar truees inseguro.
Fred
77
Sí, confiar siempre en todos los certificados SSL es inseguro por definición. Evite hacerlo si es posible.
Andrej Rommel
@AndrejRommel, ¿cuál es tu camino recomendado?
Kiquenet
2
La forma recomendada es crear un certificado SSL válido y utilizarlo adecuadamente si tiene control sobre el servidor. Terminamos creando uno usando letsencrypt.org.
Andrej Rommel
5

Se ha mencionado que antes de .NET 4.5 la propiedad de la solicitud de acceso ServicePointManagerno estaba disponible.

Aquí hay un código .NET 4.0 que le dará acceso a ServicePointcada solicitud. No le da acceso a la devolución de llamada por solicitud, pero debería permitirle obtener más detalles sobre el problema. Simplemente acceda a las propiedades scvPoint.Certificate(o ClientCertificatesi lo prefiere).

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());
}
Jesse Chisholm
fuente
¡Convenido! Pero entonces, este OP trata sobre cómo ignoreno confiar en ellos.
Jesse Chisholm
De todos modos, usando ServicePointNo siempre puedo confiar en todos los certificados SSL, ni ignorar todos los certificados , porque no ha ServerCertificateValidationCallback delegado en ServicePoint
Kiquenet
4

Por cierto, esta es la forma menos detallada de desactivar toda la validación de certificados en una aplicación determinada que conozco:

ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
Christian Findlay
fuente
4

En lugar de agregar una devolución de llamada a ServicePointManager que anulará la validación del certificado a nivel mundial, puede establecer la devolución de llamada en una instancia local de HttpClient. Este enfoque solo debería afectar a las llamadas realizadas con esa instancia de HttpClient.

Aquí hay un código de muestra que muestra cómo ignorar los errores de validación de certificados para servidores específicos podría implementarse en un controlador de 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;
    }

}
Sheldon
fuente
¿Esto no funcionará solo para .NET Core? (¿O cuando se agregó ServerCertificateCustomValidationCallback a HttpClientHandler)?
phillyslick
Esta solución debería funcionar en .Net Framework 4.5 y posterior, así como en .Net Core (aunque no lo he probado en .Net Core).
Sheldon
@Sheldon, esto fue una joya :) Utilizado en mis llamadas locales de API entre un .net y una aplicación principal .net con éxito. Buena solución sin aceptar todo.
Gran
3

Basado en la respuesta de Adam y el comentario de Rob, usé esto:

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

que filtra algo el "ignorar". Se pueden agregar otros emisores según se requiera, por supuesto. Esto se probó en .NET 2.0 ya que necesitamos admitir algunos códigos heredados.

Andrej Grobler
fuente
@karank Lo sentimos por la respuesta tardía: se puede agregar en cualquier lugar antes de la llamada real, por ejemplo. antes de llamar a request.GetResponse (). Sin embargo, tenga en cuenta que el Emisor puede contener algo más en su caso.
Andrej Grobler
3

CA5386: Las herramientas de análisis de vulnerabilidad lo alertarán sobre estos códigos.

Código correcto:

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

Para .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);
    }
}
Rich Hildebrand
fuente
2

Expresado explícitamente ...

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
fuente
0

Agregando a las respuestas de Sani y blak3r, he agregado lo siguiente al código de inicio de mi aplicación, pero en VB:

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

Parece funcionar.

MCattle
fuente
0

Consejo: También puede usar este método para rastrear certificados que vencen pronto. Esto puede salvar su tocino si descubre un certificado que está a punto de caducar y puede arreglarlo a tiempo. Bueno también para compañías de terceros: para nosotros, esto es DHL / FedEx. DHL acaba de dejar que un certificado expire, lo que nos está arruinando 3 días antes del Día de Acción de Gracias. Afortunadamente estoy para arreglarlo ... ¡esta vez!

    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
fuente
¡Asegúrate de manejar la situación en la que tu mecanismo de alerta puede tener un certificado caducado, o terminarás con un desbordamiento de pila!
Simon_Weaver
¿Qué es ProwlUtil.StepReached?
Kiquenet
Lo siento, ese es solo mi propio método para llamar a la API Prowl, que puede enviar notificaciones a mi teléfono. Sin embargo, si desea iniciar sesión, es bueno. ¡Me gusta que me molesten en mi teléfono por cosas como esta!
Simon_Weaver
0

Varias respuestas anteriores funcionan. Quería un enfoque que no tenía que seguir haciendo cambios en el código y no hice que mi código no fuera seguro. Por lo tanto, creé una lista blanca. La lista blanca se puede mantener en cualquier almacén de datos. Utilicé el archivo de configuración ya que es una lista muy pequeña.

Mi codigo esta abajo.

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

Versión Unity C # de esta solución:

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;
}
Santiago Game Lover
fuente