Que estoy tratando de conectar a una API que utiliza un certificado SSL auto-firmado. Estoy haciendo esto de usar .NET HttpWebRequest y HttpWebResponse objetos. Y me estoy haciendo una excepción que:

La conexión se cerró: no se Puede establecer una relación de confianza para el canal seguro SSL/TLS.

Entiendo lo que esto significa. Y entiendo por qué .NETA se siente se debe advertir a mí y cerrar la conexión. Pero en este caso, me gustaría sólo conectarse a la API de todos modos, el hombre-en-el-medio de los ataques a ser condenado.

Así que, ¿cómo ir sobre cómo agregar una excepción para este certificado auto-firmado? O es el enfoque de decirle HttpWebRequest/Respuesta de no validar el certificado a todos? ¿Cómo puedo hacer eso?

9 Comentarios

  1. 76

    @Domster: que funciona, pero es posible que desee aplicar un poco de seguridad mediante la comprobación de si el hash del certificado coincide con lo que usted espera. Para una versión ampliada se ve un poco como esta (basado en directo algunos de código que estamos usando):

    static readonly byte[] apiCertHash = { 0xZZ, 0xYY, ....};
    
    ///<summary>
    ///Somewhere in your application's startup/init sequence...
    ///</summary>
    void InitPhase()
    {
        //Override automatic validation of SSL server certificates.
        ServicePointManager.ServerCertificateValidationCallback =
               ValidateServerCertficate;
    }
    
    ///<summary>
    ///Validates the SSL server certificate.
    ///</summary>
    ///<param name="sender">An object that contains state information for this
    ///validation.</param>
    ///<param name="cert">The certificate used to authenticate the remote party.</param>
    ///<param name="chain">The chain of certificate authorities associated with the
    ///remote certificate.</param>
    ///<param name="sslPolicyErrors">One or more errors associated with the remote
    ///certificate.</param>
    ///<returns>Returns a boolean value that determines whether the specified
    ///certificate is accepted for authentication; true to accept or false to
    ///reject.</returns>
    private static bool ValidateServerCertficate(
            object sender,
            X509Certificate cert,
            X509Chain chain,
            SslPolicyErrors sslPolicyErrors)
    {
        if (sslPolicyErrors == SslPolicyErrors.None)
        {
            //Good certificate.
            return true;
        }
    
        log.DebugFormat("SSL certificate error: {0}", sslPolicyErrors);
    
        bool certMatch = false; //Assume failure
        byte[] certHash = cert.GetCertHash();
        if (certHash.Length == apiCertHash.Length)
        {
            certMatch = true; //Now assume success.
            for (int idx = 0; idx < certHash.Length; idx++)
            {
                if (certHash[idx] != apiCertHash[idx])
                {
                    certMatch = false; //No match
                    break;
                }
            }
        }
    
        //Return true => allow unauthenticated server,
        //       false => disallow unauthenticated server.
        return certMatch;
    }
    • Ningún comentario por el votante?
    • Probablemente alguien que prefiere la forma correcta de abajo. De todos modos, este hack funciona en un apuro, pero probablemente no debería ser la codificación de estos tipos de excepciones en… o simplemente deshabilitar la comprobación de todos juntos (a través de la sugerencia directamente a continuación) o en realidad instruir a su equipo a confiar en el certificado de…
    • La desactivación es sin duda, una opción demasiado, pero la adición de la cert de la máquina a nivel de la raíz a las autoridades de la tienda sólo puede hacerse por los administradores. Mi solución funciona en ambos sentidos.
    • Y lo entiendo completamente, pero usted lo pidió, y que aún mi conjetura en cuanto a por qué alguien de votación de su respuesta. Y a pesar de que es más trabajo, en mi humilde opinión wgthom la respuesta de abajo es todavía la más correcta.
    • por cierto, ten cuidado, creo que ServerCertificateValidationCallback es ESTÁTICA, y ni siquiera threadlocal. si no estoy equivocado, entonces, una vez establecido, se mantiene hasta que se desactive. si desea utilizar una conexión única y no en todos los demás, ser muy cuidadoso con las solicitudes paralelas..
    • Esta es la mejor manera de hacer esto. Si usted quitar la marca de verificación en contra de sslPolicyErrors, en realidad se puede garantizar la API certificado es siempre el esperado. Una cosa a tener en cuenta es que el certificado de la huella digital en el código anterior es una constante de matriz de bytes. Esto no va a compilar como escrito. Intente una estática de sólo lectura de la matriz de bytes en lugar. El compilador ahoga en esto, ya que requiere el nuevo operador ().
    • Gracias por darse cuenta de la errata @Centijo, fijo.
    • si no sabemos exactamente el servidor de la api de huellas dactilares,¿cómo podemos saber que cert deben ser utilizados

  2. 87

    Resulta, si usted sólo desea deshabilitar la validación de certificados por completo, usted puede cambiar el ServerCertificateValidationCallback en el ServicePointManager, así:

    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

    Esto va a validar todos los certificados (incluyendo inválida, caducado o auto-firmado queridos).

    • Este es inteligente y me hizo reír. +1
    • Perfecto para algunas pruebas rápidas en contra del desarrollo de las máquinas. Gracias.
    • ¿Qué alcance afecta esto – todo en el dominio de aplicación? todo en el grupo de aplicaciones? todo en la máquina?
    • Dominio de aplicación
    • A mí me funcionó
    • Pero hay que tener cuidado! RL experiencia muestra que este desarrollo hacks a menudo hace su camino en la liberación del producto: La mayoría de código peligroso en el mundo
    • Este es un hack útil en desarrollo por lo que poner un #if DEBUG #endif declaración de todo es lo menos que debe hacer para hacerlo más seguro y detener esta terminando en la producción.
    • A menos de que este chico se quita esta respuesta, vamos a ver un curioso hecho de que una respuesta incorrecta recibe mucho más votos que la correcta.
    • Esto es perfecto para mantener viva la solicitud de que no necesita validación.
    • Tristemente más votos para un hack en lugar de la solución real de arriba por @devstuff. Bien para dev, pero nunca dejar este código en producción!

  3. 44

    Nota, que en .NET 4.5 se puede reemplazar SSL de validación por HttpWebRequest sí mismo (y no a través de global delegado que afecta a todas las solicitudes):

    http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.servercertificatevalidationcallback.aspx

    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
    request.ServerCertificateValidationCallback = delegate { return true; };
    • Por favor upvote que esto vale la pena actualizar a 4.5 para!
    • No esta ciegamente aceptar todos los certificados?
    • Sí, usted tiene que adoptar la lógica de usuario devstuff
  4. 42

    Agregar el auto firmado cert para el Equipo Local de Certificación Raíz de Confianza de las Autoridades

    Puede importar el cert mediante la ejecución de la MMC como Administrador.

    Cómo Ver los Certificados con el Complemento de MMC

    • En mi humilde opinión esta es la manera más correcta; las personas son demasiado perezosos para que el código de excepciones especiales para cosas que probablemente no debería.
    • ¿Que método de trabajo para Windows Mobile 6.5? ¿7? En mi caso, yo no quiero tener que agregar un certificado local para cada dispositivo móvil que he planeado para ejecutar una versión de desarrollo en. Una buena excepción, en este caso, hace que la implementación de una tonelada más fácil. La pereza o de la eficacia, usted me dice.
    • Estás usando certificados SSL por una razón – para comprobar los extremos. Si usted desarrollar código que específicamente se trabaja en torno a eso, no vas a probar adecuadamente, y el riesgo de fuga de ese código en un entorno real. Si la instalación de un cert en el cliente es realmente mucho trabajo, ¿por qué no sólo pagar un cert de un emisor de confianza para todos los dispositivos?
    • Si me acuerdo de este caso concreto, yo habría necesitado varios comodín certs (había una media docena de Tld se conecta, todo bajo nuestro control). Esa es una difícil justificar el costo de un entorno de desarrollo. En este caso, el único código que se está «trabajado» y no probado es que una excepción no es lanzada, donde sería de otra forma. Usted debe ser la prueba de que la excepción específica en el camino, independientemente de si usted está utilizando esta solución. Y, por último, si usted no puede mantener el desarrollo del código de la producción, que tienen mucho más problemas que SSL de validación.
    • para webapps, asegúrese de reciclar su apppool o reiniciar su sitio web. personalmente, me acabo de compilar, y luego se trabajó. para nuestro wsdl cosas, el certificado de verificación que aparece a suceder en la inicialización y la caché.
    • He añadido el archivo de CA en ca de confianza con MMC, pero el .NET app no lo aceptó. La aplicación no es mía 🙁 El CA cert está bien, porque funciona si puedo añadir que en Firefox o en Cygwin y prueba. Alguna idea de por qué?

  5. 33

    El alcance de la validación de devolución de llamada se utiliza en Domster la respuesta puede ser limitada a una solicitud específica utilizando el parámetro sender en el ServerCertificateValidationCallback delegado. El siguiente ámbito de la clase utiliza esta técnica temporalmente el alambre hasta la validación de una devolución de llamada que sólo se ejecuta para un determinado objeto de solicitud.

    public class ServerCertificateValidationScope : IDisposable
    {
        private readonly RemoteCertificateValidationCallback _callback;
    
        public ServerCertificateValidationScope(object request,
            RemoteCertificateValidationCallback callback)
        {
            var previous = ServicePointManager.ServerCertificateValidationCallback;
            _callback = (sender, certificate, chain, errors) =>
                {
                    if (sender == request)
                    {
                        return callback(sender, certificate, chain, errors);
                    }
                    if (previous != null)
                    {
                        return previous(sender, certificate, chain, errors);
                    }
                    return errors == SslPolicyErrors.None;
                };
            ServicePointManager.ServerCertificateValidationCallback += _callback;
        }
    
        public void Dispose()
        {
            ServicePointManager.ServerCertificateValidationCallback -= _callback;
        }
    }

    La clase anterior puede ser utilizado para ignorar todos los errores de certificado para una solicitud específica de la siguiente manera:

    var request = WebRequest.Create(uri);
    using (new ServerCertificateValidationScope(request, delegate { return true; }))
    {
        request.GetResponse();
    }
    • Esta respuesta de las necesidades más votos 🙂 Es la respuesta más razonable a omitir la validación de certificados para una sola solicitud de uso de un objeto HttpWebRequest.
    • He añadido esto y todavía estoy recibiendo La petición fue anulado: no se Pudo crear el canal seguro SSL/TLS.
    • Esto realmente no resuelve el problema en un entorno multiproceso.
  6. 3

    A agregar como una posible ayuda para alguien más… Si quieres que pida al usuario para instalar el certificado autofirmado, puede utilizar este código (modificado de arriba).

    No se requieren derechos de administrador, se instala en los locales de los usuarios de confianza perfiles:

        private static bool ValidateServerCertficate(
            object sender,
            X509Certificate cert,
            X509Chain chain,
            SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
            {
                //Good certificate.
                return true;
            }
    
            Common.Helpers.Logger.Log.Error(string.Format("SSL certificate error: {0}", sslPolicyErrors));
            try
            {
                using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
                {
                    store.Open(OpenFlags.ReadWrite);
                    store.Add(new X509Certificate2(cert));
                    store.Close();
                }
                return true;
            }
            catch (Exception ex)
            {
                Common.Helpers.Logger.Log.Error(string.Format("SSL certificate add Error: {0}", ex.Message));
            }
    
            return false;
        }

    Esto parece funcionar bien para nuestra aplicación, y si el usuario no presiona ninguna, la comunicación no funciona.

    Actualización: 2015-12-11 – Cambiado StoreName.De la raíz a StoreName.Mi – Mi instalará en el local de los usuarios de la tienda, en lugar de Raíz. Raíz en algunos sistemas no funcionan, incluso si usted «ejecutar como administrador»

    • Este sería increíble si se trabajó en Compact Framework winCE. de la tienda.Agregar(..) no está disponible.
  7. 2

    La construcción en la respuesta de devstuff incluir sujeto y el emisor…comentarios de bienvenida…

    public class SelfSignedCertificateValidator
    {
    private class CertificateAttributes
    {
    public string Subject { get; private set; }
    public string Issuer { get; private set; }
    public string Thumbprint { get; private set; }
    public CertificateAttributes(string subject, string issuer, string thumbprint)
    {
    Subject = subject;
    Issuer = issuer;                
    Thumbprint = thumbprint.Trim(
    new char[] { '\u200e', '\u200f' } //strip any lrt and rlt markers from copy/paste
    ); 
    }
    public bool IsMatch(X509Certificate cert)
    {
    bool subjectMatches = Subject.Replace(" ", "").Equals(cert.Subject.Replace(" ", ""), StringComparison.InvariantCulture);
    bool issuerMatches = Issuer.Replace(" ", "").Equals(cert.Issuer.Replace(" ", ""), StringComparison.InvariantCulture);
    bool thumbprintMatches = Thumbprint == String.Join(" ", cert.GetCertHash().Select(h => h.ToString("x2")));
    return subjectMatches && issuerMatches && thumbprintMatches; 
    }
    }
    private readonly List<CertificateAttributes> __knownSelfSignedCertificates = new List<CertificateAttributes> {
    new CertificateAttributes(  //can paste values from "view cert" dialog
    "CN = subject.company.int", 
    "CN = issuer.company.int", 
    "f6 23 16 3d 5a d8 e5 1e 13 58 85 0a 34 9f d6 d3 c8 23 a8 f4") 
    };       
    private static bool __createdSingleton = false;
    public SelfSignedCertificateValidator()
    {
    lock (this)
    {
    if (__createdSingleton)
    throw new Exception("Only a single instance can be instanciated.");
    //Hook in validation of SSL server certificates.  
    ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertficate;
    __createdSingleton = true;
    }
    }
    ///<summary>
    ///Validates the SSL server certificate.
    ///</summary>
    ///<param name="sender">An object that contains state information for this
    ///validation.</param>
    ///<param name="cert">The certificate used to authenticate the remote party.</param>
    ///<param name="chain">The chain of certificate authorities associated with the
    ///remote certificate.</param>
    ///<param name="sslPolicyErrors">One or more errors associated with the remote
    ///certificate.</param>
    ///<returns>Returns a boolean value that determines whether the specified
    ///certificate is accepted for authentication; true to accept or false to
    ///reject.</returns>
    private bool ValidateServerCertficate(
    object sender,
    X509Certificate cert,
    X509Chain chain,
    SslPolicyErrors sslPolicyErrors)
    {
    if (sslPolicyErrors == SslPolicyErrors.None)
    return true;   //Good certificate.
    Dbg.WriteLine("SSL certificate error: {0}", sslPolicyErrors);
    return __knownSelfSignedCertificates.Any(c => c.IsMatch(cert));            
    }
    }
  8. 1

    Una cosa a tener en cuenta es que el hecho de ServicePointManager.ServerCertificateValidationCallback no parece significar que la comprobación de CRL y servername de validación no son hecho, sólo proporciona un medio para anular su resultado. Para que su servicio aún podría tomar un tiempo para conseguir una CRL, sólo tendrás que saber después de que falló en algunas comprobaciones.

  9. 1

    Yo estaba corriendo en el mismo problema que el OP, donde la solicitud web lanzaría exacta excepción. Yo tenía todo configurado correctamente pensé, el certificado se ha instalado, no me podía ubicar en el almacén del equipo igual de bien, y adjuntarlo a la solicitud en la web, y me había desactivado la verificación de los certificados en el contexto de la solicitud.

    Resultó que yo estaba corriendo en mi cuenta de usuario, y que el certificado se ha instalado en la máquina de la tienda. Esto provocó que la solicitud web para lanzar esta excepción. Para resolver el problema que yo tenía que estar ejecutando como administrador o instalar el certificado en el almacén de usuario y leer a partir de allí.

    Parece que C# es capaz de encontrar el certificado en el almacén del equipo aunque no se puede utilizar con una solicitud en la web, y que esto se traduce en que el OP de la excepción una vez que la solicitud en la web de la emisión.

    • Para los servicios de Windows puede configurar por separado certificado configuraciones por cada servicio. Si usted está escribiendo no es una aplicación de escritorio, sino un servicio, el CA cert pueden ser importados en MMC para el servicio de demonio específicamente. ¿Cuál es la diferencia entre la cuenta de usuario y la máquina cuenta? Pensé que todo en la cuenta de la máquina se aplica al usuario de forma automática.

Dejar respuesta

Please enter your comment!
Please enter your name here