Impossibile stabilire una relazione di fiducia per il canale sicuro SSL / TLS - SOAP


326

Ho una semplice chiamata al servizio Web, generata da un'app Windows (C #) 2.0 per Windows, tramite il proxy del servizio Web generato da Visual Studio, per un servizio Web scritto anche in C # (2.0). Questo ha funzionato per diversi anni e continua a farlo in una dozzina di posti dove sta funzionando.

Una nuova installazione in un nuovo sito sta riscontrando un problema. Quando si tenta di invocare il servizio Web, non riesce con il messaggio che dice:

Impossibile stabilire una relazione di fiducia per il canale sicuro SSL / TLS

L'URL del servizio Web utilizza SSL (https: //) - ma questo funziona da molto tempo (e continua a farlo) da molte altre posizioni.

Dove guardo? Potrebbe trattarsi di un problema di sicurezza tra Windows e .NET unico per questa installazione? In tal caso, dove posso impostare relazioni di fiducia? Mi sono perso!


Nel mio caso questo errore è stato causato dall'inoltro dell'indirizzo IP.
cja,

Risposte:


166

Pensieri (basati sul dolore in passato):

  • hai DNS e line-of-sight per il server?
  • stai usando il nome corretto dal certificato?
  • il certificato è ancora valido?
  • è un bilanciamento del carico mal configurato che rovina le cose?
  • l'orologio della nuova macchina server è impostato correttamente (ovvero in modo che l'ora UTC sia corretta [ignora l'ora locale, è in gran parte irrilevante]) - questo è certamente importante per WCF, quindi potrebbe avere un impatto su SOAP normale?
  • esiste un problema relativo alla catena di attendibilità del certificato? se navighi dal server al servizio soap, puoi ottenere SSL?
  • in relazione a quanto sopra - il certificato è stato installato nella posizione corretta? (potrebbe essere necessaria una copia nelle autorità di certificazione radice attendibili)
  • il proxy a livello di macchina del server è impostato correttamente? (quale diverso dal proxy dell'utente); vedere proxycfg per XP / 2003 (non sono sicuro di Vista, ecc.)

2
1) Il servizio web è sul web. Possiamo navigare tramite un browser. 2) La nuova macchina non è un server - è un desktop che esegue la mia app, che raccoglie informazioni sugli ordini e caricamenti tramite il servizio SOAP 3) Sì, possiamo accedervi. 4) Questa è una novità per me: proxy a livello di macchina?
Rob Schripsema,

2
Sì; il codice non utilizza le impostazioni del proxy IE; utilizza un negozio separato ... è importante che sia configurato (se si utilizza un proxy). Su XP, l'opzione più semplice è (IIRC) "proxycfg -i" per importare le impostazioni di IE.
Marc Gravell

11
Grazie Marc. Questo mi ha aiutato e il problema era che il server aveva un certificato firmato da una CA di terze parti di cui non mi ero ancora fidato. La soluzione consisteva nell'aggiungere quella CA all'elenco delle CA radice attendibili.
p

1
Il computer con questa eccezione non è stato in grado di sincronizzare l'ora del sistema utilizzando i server dell'ora. Ho dovuto entrare e sincronizzare manualmente il tempo prima che funzionasse.
Chris - Haddox Technologies,

4
Puoi ottenerlo se hai utilizzato Fiddler per eseguire il debug delle chiamate di servizio e hai utilizzato la modalità di intercettazione del certificato. Rimuovi l'intercettazione nelle opzioni del violinista e dovresti essere bravo
Ruskin,

363

I seguenti frammenti risolveranno il caso in cui c'è qualcosa di sbagliato nel certificato SSL sul server che stai chiamando. Ad esempio, potrebbe essere autofirmato o il nome host tra il certificato e il server potrebbe non corrispondere.

Questo è pericoloso se stai chiamando un server al di fuori del tuo controllo diretto, poiché non puoi più essere sicuro di parlare al server a cui pensi di essere connesso. Tuttavia, se hai a che fare con server interni e ottenere un certificato "corretto" non è pratico, usa quanto segue per dire al servizio web di ignorare i problemi del certificato e coraggiosamente soldato.

I primi due usano espressioni lambda, il terzo usa un codice normale. Il primo accetta qualsiasi certificato. Gli ultimi due verificano almeno che il nome host nel certificato sia quello che ti aspetti.
... spero che lo trovi utile

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

6
La mia esperienza con ServicePointManager. Qualsiasi modifica ad esso influirebbe sull'intero dominio dell'app. Sebbene la risposta sia spiegata in modo molto chiaro come questo può essere applicato, mi piace gettare questo punto.
Amzath,

L'impostazione del callback funziona in .NET 4.5 per me, ma non in 4.6 4.6
RJB

@Amzath Qualche suggerimento su come resettarlo dopo che una particolare richiesta è stata completata? Una persona potrebbe aver bisogno di fare una richiesta a un server non certificato, quindi rimettere le cose come erano.
Isaac Lyman,

1
@Isaac Lyman: ServicePointManager.ServerCertificateValidationCallback = null;dovrebbe ripristinare il comportamento predefinito.
Mike Chamberlain,

1
@MikeChamberlain L'unico problema con il tuo suggerimento è che le richieste simultanee potrebbero essere rese insicure poiché hai a che fare con un'impostazione globale dell'app.
Isaac Lyman,

178

La semplicissima soluzione "catch all" è questa:

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

La soluzione di sebastian-castaldi è un po 'più dettagliata.


21
Ho appena inserito questo in una #If CONFIG = "Debug"dichiarazione in modo che sia attivato solo in modalità debug. Funziona benissimo!
cjbarth,

1
I dettagli possono essere buoni, ma c'è qualcosa da dire anche per una riga di codice rapida, breve e facile. Questo codice è breve e fa il trucco.
allen1,

agirà solo sull'Azione corrente (ad esempio, viene utilizzato ASP MVC)? o verrà impostato come comportamento predefinito per l'applicazione ASP.NET?
JeeShen Lee,

2
Questo dovrebbe essere usato solo a scopo di test, questa soluzione si fida di qualsiasi certificato, anche non valido / scaduto
Shenron,

1
Come spiegato nei commenti sopra, questo non verifica se la connessione SSL è più valida. Quindi la connessione tra il tuo sistema e altri sistemi potrebbe essere compromessa. È sempre una questione di ciò di cui hai bisogno.
Remy,

35

Personalmente mi piace di più la seguente soluzione:

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

... quindi prima di richiedere di ottenere l'errore, procedi come segue

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

Trovato questo dopo aver consultato la soluzione di Luke


4
Vedi la risposta di Sebastian Castaldi per avvertenze sulla sicurezza di questo approccio.
Edward Brey,

Qual è il rischio per la sicurezza di utilizzarlo in produzione?
Amjad,

@Amjad il rischio per la sicurezza è che elimini completamente qualsiasi vantaggio derivante dall'uso di SSL / TLS. Il server può presentare qualsiasi certificato gli piaccia e questo codice ignorerà l'errore
1800 INFORMAZIONI

18

Se stai usando Windows 2003, puoi provare questo:

Apri Microsoft Management Console (Start -> Esegui -> mmc.exe);

Scegli File -> Aggiungi / Rimuovi snap-in;

Nella scheda Autonomo, scegli Aggiungi;

Scegli lo snap-in Certificati e fai clic su Aggiungi;

Nella procedura guidata, selezionare l'account del computer, quindi selezionare Computer locale. Premere Fine per terminare la procedura guidata;

Chiudi la finestra di dialogo Aggiungi / Rimuovi snap-in;

Passa a Certificati (computer locale) e scegli un negozio da importare:

Se si dispone del certificato CA principale per la società che ha emesso il certificato, selezionare Autorità di certificazione radice attendibili;

Se si dispone del certificato per il server stesso, selezionare Altre persone

Fai clic con il pulsante destro del mouse sul negozio e scegli Tutte le attività -> Importa

Segui la procedura guidata e fornisci il file del certificato che hai;

Successivamente, riavvia semplicemente IIS e prova a chiamare nuovamente il servizio Web.

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


2
Questo mi ha reso parte del processo, ma avevo bisogno di avere il certificato nella sezione Autorità di certificazione radice affidabili per farlo funzionare. Secondo blogs.msdn.com/b/jpsanders/archive/2009/09/16/…
Jacob Ewald

17

Se non vuoi fidarti ciecamente di tutti e fare un'eccezione di fiducia solo per determinati host, la seguente soluzione è più appropriata.

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

Quindi chiama Ssl.EnableTrustedHosts all'avvio dell'app.


Sì, rileggere Sì, penso di aver letto male la prima volta
Shiv

Qual è il rischio per la sicurezza di fidarsi di tutti i certificati in produzione?
Amjad,

@Amjad il rischio per la sicurezza è che chiunque tra il client e il server possa inserirsi nel mezzo delle comunicazioni, utilizzare il proprio certificato SSL e leggere tutto il traffico tra client e server. In questo modo si annulla efficacemente SSL.
Rob Prouse,

Dovrebbe funzionare quando iam utilizza il componente aggiuntivo WCF per generare classi da wsdl?
Kamil,

7

Luke ha scritto un articolo abbastanza buono su questo ... piuttosto semplice ... provalo

La soluzione di Luke

Motivo (citazione dal suo articolo (meno imprecazioni)) ".. Il problema con il codice sopra è che non funziona se il tuo certificato non è valido. Perché dovrei pubblicare su una pagina web con un certificato SSL non valido? Perché Sono a buon mercato e non mi andava di pagare Verisign o uno degli altri ** - * s per un certificato nella mia casella di test, quindi l'ho autofirmato. Quando ho inviato la richiesta ho ricevuto una bella eccezione:

System.Net.WebException La connessione sottostante è stata chiusa. Impossibile stabilire una relazione di fiducia con il server remoto.

Non so te, ma per me quell'eccezione sembrava qualcosa che sarebbe stata causata da un errore sciocco nel mio codice che stava causando il fallimento del POST. Così ho continuato a cercare, modificare e fare ogni sorta di cose strane. Solo dopo aver cercato su Google la cosa *** n ho scoperto che il comportamento predefinito dopo aver incontrato un certificato SSL non valido è quello di lanciare questa eccezione. .."


1
Questa soluzione è obsoleta per .Net 4.5. Se vuoi solo accettare tutti i certificati, vedi Sebastian Castaldi o la mia risposta più avanti.
Remy,


3

Ho appena riscontrato questo problema. La mia risoluzione era quella di aggiornare l'ora del sistema sincronizzando manualmente i server dell'ora. Per fare ciò puoi:

  • Fare clic con il tasto destro del mouse sull'orologio nella barra delle attività
  • Selezionare Adjust Date/Time
  • Seleziona la Internet Timescheda
  • Clic Change Settings
  • Selezionare Update Now

Nel mio caso questo si stava sincronizzando in modo errato, quindi ho dovuto fare clic più volte prima che si aggiornasse correttamente. Se l'aggiornamento continua in modo errato, puoi anche provare a utilizzare un server orario diverso dal menu a discesa del server.


MUCCA SACRA. Mi sono imbattuto in questa cosa esatta. Grazie per la correzione semplice!
Germ

3

Prova questo:

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

Si noti che è necessario lavorare almeno con il framework .NET 4.5


3

Ho avuto un problema simile .NETnell'app in Internet Explorer.

Ho risolto il problema aggiungendo il certificato (certificato VeriSign Classe 3 nel mio caso) ai certificati degli editori fidati.

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

Puoi ottenere il certificato se lo esporti da:

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

Grazie


1

Ho avuto questo errore in esecuzione su un server web con url come:

a.b.domain.com

ma non c'era nessun certificato per questo, quindi ho ricevuto un DNS chiamato

a_b.domain.com

Basta dare un suggerimento a questa soluzione qui poiché questa è arrivata in cima a Google.


Nel mio caso, il sito Web è stato configurato con un certificato ssl jolly (* .abcd.com). Quando configurato, l'associazione del sito Web era simile a xyz-abcd.com che causava il problema.
sree

1

Per coloro che stanno riscontrando questo problema attraverso un lato client VS una volta aggiunto correttamente un riferimento al servizio e tentando di eseguire la prima chiamata ha ottenuto questa eccezione: "La connessione sottostante è stata chiusa: impossibile stabilire una relazione di fiducia per il canale sicuro SSL / TLS" Se stai usando (come nel mio caso) un URL endpoint con l'indirizzo IP e hai ottenuto questa eccezione, quindi probabilmente dovrai aggiungere di nuovo il riferimento al servizio procedendo come segue:

  • Apri l'URL dell'endpoint su Internet Explorer.
  • Fai clic sull'errore del certificato (icona rossa nella barra degli indirizzi)
  • Fai clic su Visualizza certificati.
  • Prendi l'emissione per: "nome" e sostituisci l'indirizzo IP o qualunque nome stessimo usando e ottenendo l'errore per questo "nome".

Riprova :). Grazie


0

Nel mio caso stavo provando a testare SSL nel mio ambiente Visual Studio usando IIS 7.

Questo è quello che ho finito per farlo funzionare:

  • Sotto il mio sito nella sezione "Associazioni ..." a destra in IIS, ho dovuto aggiungere l'associazione "https" alla porta 443 e selezionare "Certificato di sviluppo IIS Express".

  • Sotto il mio sito nella sezione "Impostazioni avanzate ..." sulla destra ho dovuto modificare i "Protocolli abilitati" da "http" a "https".

  • Sotto l'icona "Impostazioni SSL" ho selezionato "Accetta" per i certificati client.

  • Quindi ho dovuto riciclare il pool di app.

  • Ho anche dovuto importare il certificato host locale nel mio negozio personale usando mmc.exe.

Il mio web.configfile era già configurato correttamente, quindi dopo aver risolto tutto quanto sopra, sono riuscito a continuare i miei test.


come è stato configurato il tuo web.config?
Chazt3n

@ Chazt3n Non saprei dirtelo, era un po 'di tempo fa, ma sarebbe stata una configurazione di associazione http di base, in genere uso svcutil per generare informazioni di configurazione per le informazioni sul client del servizio web.
Popo

0

La mia soluzione (VB.Net, la versione "staging" (UAT) di questa applicazione deve funzionare con il certificato "staging" ma non influire sulle richieste una volta che si trovano sul sito live):

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

-3

Se non funziona un sertificato non valido, quando ServerCertificateValidationCallback restituisce true; My ServerCertificateValidationCallback code:

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

Il mio codice che gli impediti eseguono ServerCertificateValidationCallback:

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

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

Ho disabilitato il codice CertificateValidation e ServerCertificateValidationCallback in esecuzione molto bene


Non si dovrebbe mai disabilitare alcuna convalida del certificato. Risolvi invece il problema che causa la convalida non riuscita.
Dan

Qual è il rischio per la sicurezza di utilizzarlo in produzione?
Amjad,
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.