No se pudo establecer una relación de confianza para el canal seguro SSL / TLS - SOAP

326

Tengo una llamada de servicio web simple, generada por una aplicación de Windows .NET (C #) 2.0, a través del proxy de servicio web generado por Visual Studio, para un servicio web también escrito en C # (2.0). Esto ha funcionado durante varios años, y continúa haciéndolo en la docena de lugares donde se está ejecutando.

Una nueva instalación en un nuevo sitio se encuentra con un problema. Al intentar invocar el servicio web, falla con el mensaje que dice:

No se pudo establecer una relación de confianza para el canal seguro SSL / TLS

La URL del servicio web utiliza SSL (https: //), pero esto ha estado funcionando durante mucho tiempo (y continúa haciéndolo) desde muchas otras ubicaciones.

Donde miro ¿Podría ser un problema de seguridad entre Windows y .NET que sea exclusivo de esta instalación? Si es así, ¿dónde configuro relaciones de confianza? ¡Estoy perdido!

Rob Schripsema
fuente
En mi caso, este error fue causado por el reenvío de dirección IP.
cja

Respuestas:

166

Pensamientos (basados ​​en el dolor en el pasado):

  • ¿tiene DNS y línea de visión para el servidor?
  • ¿Está utilizando el nombre correcto del certificado?
  • ¿El certificado sigue siendo válido?
  • ¿Un equilibrador de carga mal configurado está estropeando las cosas?
  • ¿la nueva máquina del servidor tiene el reloj configurado correctamente (es decir, para que la hora UTC sea correcta [ignore la hora local, es en gran medida irrelevante]) - esto ciertamente es importante para WCF, por lo que puede afectar el SOAP regular?
  • ¿Hay algún problema con la cadena de confianza del certificado? si navega desde el servidor al servicio de telenovelas, ¿puede obtener SSL?
  • relacionado con lo anterior: ¿se ha instalado el certificado en la ubicación correcta? (es posible que necesite una copia en las autoridades de certificación raíz de confianza)
  • ¿está configurado correctamente el proxy de nivel de máquina del servidor? (que es diferente al proxy del usuario); ver proxycfg para XP / 2003 (no estoy seguro acerca de Vista, etc.)
Marc Gravell
fuente
2
1) El servicio web está en la web. Podemos navegar a través de un navegador. 2) La nueva máquina no es un servidor: es un escritorio que ejecuta mi aplicación, que recopila información de pedidos y carga a través del servicio SOAP 3) Sí, podemos buscarlo. 4) Esto es nuevo para mí: ¿proxy de nivel de máquina?
Rob Schripsema el
2
Si; el código no usa la configuración del proxy IE; usa una tienda separada ... es importante que esté configurado (si está usando un proxy). En XP, la opción más fácil es (IIRC) "proxycfg -i" para importar la configuración de IE.
Marc Gravell
11
Gracias Marc Esto me ayudó, y el problema era que el servidor tenía un certificado firmado por una CA de terceros en la que todavía no había confiado. La solución fue agregar esa CA a la lista de CA raíz de confianza.
p.campbell
1
La computadora que tenía esta excepción no pudo sincronizar la hora del sistema usando los servidores de hora. Tuve que entrar y sincronizar manualmente el tiempo antes de que funcionara.
Chris - Haddox Technologies
44
Puede obtener esto si ha estado utilizando Fiddler para depurar llamadas de servicio y ha utilizado su modo de interceptación de certificados. Simplemente elimine la intercepción en las opciones del violinista y debería ser bueno
Ruskin
363

Los siguientes fragmentos solucionarán el caso de que haya algo mal con el certificado SSL en el servidor al que está llamando. Por ejemplo, puede estar autofirmado o el nombre de host entre el certificado y el servidor puede no coincidir.

Esto es peligroso si está llamando a un servidor fuera de su control directo, ya que ya no puede estar tan seguro de estar hablando con el servidor al que cree que está conectado. Sin embargo, si está tratando con servidores internos y obtener un certificado "correcto" no es práctico, use lo siguiente para indicarle al servicio web que ignore los problemas del certificado y continúe valientemente.

Los dos primeros usan expresiones lambda, el tercero usa código regular. El primero acepta cualquier certificado. Los dos últimos al menos verifican que el nombre de host en el certificado sea el que espera.
... espero que te sea útil

//Trust all certificates
System.Net.ServicePointManager.ServerCertificateValidationCallback =
    ((sender, certificate, chain, sslPolicyErrors) => true);

// trust sender
System.Net.ServicePointManager.ServerCertificateValidationCallback
                = ((sender, cert, chain, errors) => cert.Subject.Contains("YourServerName"));

// validate cert by calling a function
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);

// callback used to validate the certificate in an SSL conversation
private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors)
{
    bool result = cert.Subject.Contains("YourServerName");
    return result;
}
Sebastian Castaldi
fuente
66
Mi experiencia con ServicePointManager. Cualquier cambio en él afectaría a todo el dominio de la aplicación. Aunque la respuesta se explica muy claramente cómo se puede aplicar esto, me gusta lanzar este punto.
Amzath
Configurar la devolución de llamada funciona en .NET 4.5 para mí, pero no en .NET 4.6
RJB el
@Amzath ¿Alguna sugerencia sobre cómo restablecer esto después de que se complete una solicitud en particular? Es posible que una persona necesite hacer una solicitud a un servidor no certificado y luego volver a poner las cosas como estaban.
Isaac Lyman
1
@Isaac Lyman: ServicePointManager.ServerCertificateValidationCallback = null;debería volver al comportamiento predeterminado.
Mike Chamberlain
1
@MikeChamberlain El único problema con su sugerencia es que las solicitudes concurrentes pueden volverse inseguras ya que se trata de una configuración de aplicación global.
Isaac Lyman
178

La solución muy simple de "capturar todo" es esta:

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

La solución de sebastian-castaldi es un poco más detallada.

Remy
fuente
21
Acabo de poner esto en una #If CONFIG = "Debug"declaración para que solo se active cuando está en modo de depuración. ¡Funciona muy bien!
cjbarth
1
Los detalles pueden ser buenos, pero también hay algo que decir para una línea de código rápida, corta y fácil. Este código es corto y hace el truco.
allen1
¿actuará esto solo en la Acción actual (por ejemplo, se usa ASP MVC)? o se establecerá como el comportamiento predeterminado para la aplicación ASP.NET?
JeeShen Lee
2
Esto debe usarse solo para fines de prueba, esta solución confía en cualquier certificado, incluso los inválidos / caducados
Shenron
1
Como se explicó en los comentarios anteriores, esto no verifica si la conexión SSL ya es válida. Por lo tanto, la conexión entre su sistema y otros sistemas puede verse comprometida. Siempre se trata de para qué necesitas esto.
Remy
35

Personalmente, me gusta más la siguiente solución:

using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

... luego, antes de solicitar el error, haga lo siguiente

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

Encontré esto después de consultar la solución de Luke

Cusman
fuente
44
Vea la respuesta de Sebastian Castaldi para las advertencias de seguridad de este enfoque.
Edward Brey
¿Cuál es el riesgo de seguridad de usar esto en la producción?
Amjad
@Amjad, el riesgo de seguridad es que elude completamente cualquier beneficio de usar SSL / TLS. El servidor puede presentar cualquier certificado que desee, y este código ignorará el error
1800 INFORMACIÓN
18

Si está utilizando Windows 2003, puede intentar esto:

Abra Microsoft Management Console (Inicio -> Ejecutar -> mmc.exe);

Elija Archivo -> Agregar / Eliminar complemento;

En la pestaña Independiente, elija Agregar;

Elija el complemento Certificados y haga clic en Agregar;

En el asistente, elija la cuenta de la computadora y luego elija la computadora local. Presione Finalizar para finalizar el asistente;

Cierre el cuadro de diálogo Agregar o quitar complemento;

Vaya a Certificados (equipo local) y elija una tienda para importar:

Si tiene el certificado de CA raíz para la compañía que emitió el certificado, elija Autoridades confiables de certificación raíz;

Si tiene el certificado para el servidor, elija Otras personas

Haga clic derecho en la tienda y elija Todas las tareas -> Importar

Siga al asistente y proporcione el archivo de certificado que tiene;

Después de eso, simplemente reinicie IIS e intente llamar al servicio web nuevamente.

Referencia: http://www.outsystems.com/NetworkForums/ViewTopic.aspx?Topic=Web-Services:-Could-not-establish-trust-relationship-for-the-SSL/TLS- ...

Diogo
fuente
2
Esto me hizo parte del camino, pero necesitaba tener el certificado en la sección Autoridades de certificación raíz de confianza para que funcione. Según blogs.msdn.com/b/jpsanders/archive/2009/09/16/…
Jacob Ewald
17

Si no desea confiar ciegamente en todos y hacer una excepción de confianza solo para ciertos hosts, la siguiente solución es más adecuada.

public static class Ssl
{
    private static readonly string[] TrustedHosts = new[] {
      "host1.domain.com", 
      "host2.domain.com"
    };

    public static void EnableTrustedHosts()
    {
      ServicePointManager.ServerCertificateValidationCallback = 
      (sender, certificate, chain, errors) =>
      {
        if (errors == SslPolicyErrors.None)
        {
          return true;
        }

        var request = sender as HttpWebRequest;
        if (request != null)
        {
          return TrustedHosts.Contains(request.RequestUri.Host);
        }

        return false;
      };
    }
}

Luego simplemente llame a Ssl.EnableTrustedHosts cuando se inicie su aplicación.

Gregor Slavec
fuente
@thelem Sí releyendo Creo que debo haber leído mal la primera vez
Shiv
¿Cuál es el riesgo de seguridad de confiar en todos los certificados en producción?
Amjad
@Amjad, el riesgo de seguridad es que cualquier persona entre el cliente y el servidor puede insertarse en medio de las comunicaciones, usar su propio certificado SSL y leer todo el tráfico entre el cliente y el servidor. Hacer esto efectivamente invalida SSL.
Rob Prouse
¿Debería funcionar cuando iam usa el complemento WCF para generar clases desde wsdl?
Kamil
7

Luke escribió un artículo bastante bueno sobre esto ... bastante sencillo ... pruébalo

La solución de Luke

Motivo (cita de su artículo (menos maldición)) ".. El problema con el código anterior es que no funciona si su certificado no es válido. ¿Por qué estaría publicando en una página web con un certificado SSL no válido? Porque Soy barato y no tenía ganas de pagarle a Verisign o uno de los otros ** - * s por un certificado en mi caja de prueba, así que lo firmé. Cuando envié la solicitud, recibí una hermosa excepción:

System.Net.WebException La conexión subyacente se cerró. No se pudo establecer una relación de confianza con el servidor remoto.

No sé sobre usted, pero para mí esa excepción parecía algo que sería causado por un error tonto en mi código que estaba causando que fallara la POST. Así que seguí buscando, ajustando y haciendo todo tipo de cosas raras. Solo después de buscar en Google lo *** n descubrí que el comportamiento predeterminado después de encontrar un certificado SSL no válido es lanzar esta misma excepción. .. "

Hans
fuente
1
Esta solución está en desuso para .Net 4.5. Si solo quiere aceptar todos los certificados, vea Sebastian Castaldi o mi respuesta más abajo.
Remy
7

Herramienta de diagnóstico SSL de Microsoft puede ayudar a identificar el problema.

ACTUALIZAR el enlace se ha solucionado ahora.

sipwiz
fuente
77
A partir de hoy (agosto de 2012), ese enlace ahora está roto.
cenizas999
Busqué en el directorio de descargas y ya no hay ninguna herramienta de diagnóstico SSL disponible. :(
SASS_Shooter
2
Vamos a arreglar el enlace. Corrígeme
Amzath
3

Acabo de encontrar este problema. Mi resolución fue actualizar la hora del sistema sincronizándola manualmente con los servidores de hora. Para hacer esto puedes:

  • Haga clic derecho en el reloj en la barra de tareas
  • Seleccione Adjust Date/Time
  • Selecciona el Internet Time pestaña
  • Hacer clic Change Settings
  • Seleccione Update Now

En mi caso, esto se estaba sincronizando incorrectamente, así que tuve que hacer clic varias veces antes de que se actualizara correctamente. Si continúa actualizándose incorrectamente, incluso puede intentar usar un servidor horario diferente del desplegable del servidor.

Chris - Tecnologías Haddox
fuente
VACA SANTA Ran chocó con esto exactamente. Gracias por la solución fácil!
TheGerm
3

Prueba esto:

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

Tenga en cuenta que debe trabajar al menos con 4.5 .NET framework

Manuel Roldan
fuente
3

Tuve un problema similar en la .NETaplicación en Internet Explorer.

Resolví el problema agregando el certificado (certificado VeriSign Clase 3 en mi caso) a certificados de editores de confianza.

Go to Internet Options-> Content -> Publishers and import it

Puede obtener el certificado si lo exporta desde:

Internet Options-> Content -> Certificates -> Intermediate Certification Authorities -> VeriSign Class 3 Public Primary Certification Authority - G5

Gracias

debiasej
fuente
1

Tuve este error ejecutándose contra un servidor web con URL como:

a.b.domain.com

pero no había certificado para ello, así que recibí un DNS llamado

a_b.domain.com

Solo estoy dando una pista a esta solución aquí, ya que esto apareció en Google.

Thomas Koelle
fuente
En mi caso, el sitio web se configuró con un certificado SSL comodín (* .abcd.com). Cuando se configuró, el enlace del sitio web era como xyz-abcd.com que causaba el problema.
sree
1

Para aquellos que tienen este problema a través del lado del cliente VS, una vez que agregaron con éxito una referencia de servicio y trataron de ejecutar la primera llamada obtuvieron esta excepción: "La conexión subyacente se cerró: no se pudo establecer una relación de confianza para el canal seguro SSL / TLS" Si está utilizando (como mi caso) una URL de punto final con la dirección IP y obtuvo esta excepción, entonces probablemente deba volver a agregar la referencia de servicio siguiendo estos pasos:

  • Abra la URL del punto final en Internet Explorer.
  • Haga clic en el error del certificado (icono rojo en la barra de direcciones)
  • Haga clic en Ver certificados.
  • Tome el emitido a: "nombre" y reemplace la dirección IP o cualquier nombre que estemos usando y obtenga el error para este "nombre".

Inténtalo de nuevo :). Gracias

Ernesto
fuente
0

En mi caso, estaba tratando de probar SSL en mi entorno de Visual Studio usando IIS 7.

Esto es lo que terminé haciendo para que funcione:

  • En mi sitio, en la sección 'Enlaces ...' a la derecha en IIS, tuve que agregar el enlace 'https' al puerto 443 y seleccionar "Certificado de desarrollo de IIS Express".

  • En mi sitio, en la sección 'Configuración avanzada ...' a la derecha, tuve que cambiar los 'Protocolos habilitados' de "http" a "https".

  • Debajo del icono 'Configuración de SSL', seleccioné 'Aceptar' para los certificados de cliente.

  • Luego tuve que reciclar el grupo de aplicaciones.

  • También tuve que importar el certificado de host local en mi tienda personal usando mmc.exe.

Mi web.configarchivo ya estaba configurado correctamente, así que después de resolver todo lo anterior, pude continuar con mis pruebas.

Popo
fuente
¿Cómo se configuró su web.config?
Chazt3n
@ Chazt3n No podría decirte, eso fue hace un tiempo, pero hubiera sido una configuración básica de enlace http, normalmente uso svcutil para generar información de configuración para la información del cliente del servicio web.
Popo
0

Mi solución (VB.Net, la versión "provisional" (UAT) de esta aplicación debe funcionar con el certificado "provisional" pero no afectar las solicitudes una vez que están en el sitio activo):

    ...
        Dim url As String = ConfigurationManager.AppSettings("APIURL") & "token"
        If url.ToLower().Contains("staging") Then
           System.Net.ServicePointManager.ServerCertificateValidationCallback = AddressOf AcceptAllCertifications
        End If
    ...

    Private  Function AcceptAllCertifications(ByVal sender As Object, ByVal certification As System.Security.Cryptography.X509Certificates.X509Certificate, ByVal chain As System.Security.Cryptography.X509Certificates.X509Chain, ByVal sslPolicyErrors As System.Net.Security.SslPolicyErrors) As Boolean
        Return True
    End Function
GreenRock
fuente
-3

Si no funciona mal sertificate, cuando ServerCertificateValidationCallback devuelve verdadero; Mi código de ServerCertificateValidationCallback:

ServicePointManager.ServerCertificateValidationCallback += delegate
{
    LogWriter.LogInfo("Проверка сертификата отключена, на уровне ServerCertificateValidationCallback");
    return true;
};

Mi código que impidió ejecutar ServerCertificateValidationCallback:

     if (!(ServicePointManager.CertificatePolicy is CertificateValidation))
    {
        CertificateValidation certValidate = new CertificateValidation();
        certValidate.ValidatingError += new CertificateValidation.ValidateCertificateEventHandler(this.OnValidateCertificateError);
        ServicePointManager.CertificatePolicy = certValidate;
    }

Función OnValidateCertificateError:

private void OnValidateCertificateError(object sender, CertificateValidationEventArgs e)
{
    string msg = string.Format(Strings.OnValidateCertificateError, e.Request.RequestUri, e.Certificate.GetName(), e.Problem, new Win32Exception(e.Problem).Message);
    LogWriter.LogError(msg);
    //Message.ShowError(msg);
}

Deshabilité el código CertificateValidation y ServerCertificateValidationCallback funcionando muy bien

Roberto Gata
fuente
Nunca debe deshabilitar ninguna validación de certificado. En su lugar, solucione el problema que causa la validación errónea.
Dan
¿Cuál es el riesgo de seguridad de usar esto en la producción?
Amjad