Disabilitare il fallback SSL e utilizzare solo TLS per le connessioni in uscita in .NET? (Attenuazione del barboncino)


106

Sto cercando di mitigare la nostra vulnerabilità all'attacco di fallback Poodle SSL 3.0 . I nostri amministratori hanno già iniziato a disabilitare SSL a favore di TLS per le connessioni in entrata ai nostri server. E abbiamo anche consigliato al nostro team di disabilitare SSL nei loro browser web. Sto ora esaminando la nostra base di codice .NET, che avvia connessioni HTTPS con vari servizi tramite System.Net.HttpWebRequest . Credo che queste connessioni potrebbero essere vulnerabili a un attacco MITM se consentissero il fallback da TLS a SSL. Ecco cosa ho determinato finora. Qualcuno potrebbe ricontrollare questo per verificare che ho ragione? Questa vulnerabilità è nuova di zecca, quindi devo ancora vedere alcuna guida da Microsoft su come mitigarla in .NET:

  1. I protocolli consentiti per la classe System.Net.Security.SslStream, che è alla base della comunicazione sicura in .NET, vengono impostati globalmente per ogni AppDomain tramite la proprietà System.Net.ServicePointManager.SecurityProtocol .

  2. Il valore predefinito di questa proprietà in .NET 4.5 è Ssl3 | Tls(anche se non riesco a trovare la documentazione per eseguire il backup). SecurityProtocolType è un'enumerazione con l'attributo Flags, quindi è un OR bit per bit di questi due valori. Puoi verificarlo nel tuo ambiente con questa riga di codice:

    Console.WriteLine (System.Net.ServicePointManager.SecurityProtocol.ToString ());

  3. Questo dovrebbe essere cambiato solo Tls, o forse Tls12, prima di avviare qualsiasi connessione nella tua app:

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

  4. Importante: poiché la proprietà supporta più flag bit per bit, presumo che SslStream non eseguirà automaticamente il fallback su altri protocolli non specificati durante l'handshake. Altrimenti, quale sarebbe il punto di supportare più flag?

Aggiornamento su TLS 1.0 vs 1.1 / 1.2:

Secondo l'esperto di sicurezza di Google Adam Langley, TLS 1.0 è stato successivamente ritenuto vulnerabile a POODLE se non implementato correttamente , quindi dovresti considerare di passare esclusivamente a TLS 1.2.

Aggiornamento per .NET Framework 4.7 e versioni successive:

Come accennato di seguito dal Prof Von Lemongargle , a partire dalla versione 4.7 di .NET Framework, non è necessario utilizzare questo hack poiché l'impostazione predefinita consentirà al sistema operativo di scegliere la versione del protocollo TLS più sicura. Per ulteriori informazioni, vedere le procedure consigliate per Transport Layer Security (TLS) con .NET Framework .


1
Per quanto riguarda il punto 2 sopra: vedi referencesource.microsoft.com/#System/net/System/Net/… SslProtocols "Default = Ssl3 | Tls"
Dai Bok

1
@Dai Bok L'impostazione predefinita ora è l'opzione SystemDefault docs.microsoft.com/en-us/dotnet/api/…
MarwaAhmad

@MarwaAhmad se questo è il caso, il riferimento al codice sorgente nel mio collegamento non riflette il valore predefinito (48 | 192). Se impostato su nessuno (0), dovrebbe tornare all'impostazione predefinita del sistema. Questo mi puzza e probabilmente lo testerei prima di apportare modifiche in quanto potrebbe portare a una configurazione errata ... e alla disattivazione dei protocolli sul framework .net sbagliato ...
Dai Bok

Risposte:


137

Stiamo facendo la stessa cosa. Per supportare solo TLS 1.2 e nessun protocollo SSL, puoi farlo:

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

SecurityProtocolType.Tls è solo TLS 1.0, non tutte le versioni TLS.

A fianco: se vuoi controllare che il tuo sito non consenta connessioni SSL, puoi farlo qui (non credo che questo sarà influenzato dall'impostazione di cui sopra, abbiamo dovuto modificare il registro per forzare IIS a utilizzare TLS per le connessioni in entrata): https://www.ssllabs.com/ssltest/index.html

Per disabilitare SSL 2.0 e 3.0 in IIS, vedere questa pagina: https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html


Destra. Buona idea per supportare anche le versioni più recenti di TLS: a prova di futuro.
Jordan Rieger

1
E a beneficio di altri, la modifica del registro che hai menzionato può essere eseguita anche con questi passaggi: serverfault.com/a/637263/98656 . In Windows Server 2003-2012 R2 i protocolli sono controllati da flag in HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ Schannel \ Protocols. Per disabilitare SSLv3, crea una sottochiave nella posizione sopra denominata "SSL 3.0" e, sotto di essa, una sottochiave denominata "Server" e, al di sotto, un valore DWORD denominato "Abilitato", impostato su 0. Dovresti anche disabilitare SSL 2.0 nello stesso modo.
Jordan Rieger

4
@ScotterMonkey È sufficiente impostare System.Net.ServicePointManager.SecurityProtocol se si stanno avviando connessioni in uscita da codice .NET, ad esempio connettendosi a un servizio Web o API da codice personalizzato in esecuzione sul server. Se si esegue solo un semplice sito Web e si accettano solo connessioni in entrata dai browser, la correzione del registro è sufficiente.
Jordan Rieger

7
Nota: viene visualizzato SecurityProtocolType.Tls11e i SecurityProtocolType.Tls12valori enum sono disponibili solo in ASP.net 4.5 e versioni successive. Non sono sicuro di cosa dovremmo fare per le basi di codice precedenti in esecuzione su 2.0 se TLS 1.0 andasse nel dimenticatoio.
Sam

1
@AnishV Hai inserito quella riga di codice nell'inizializzazione della tua app, prima di qualsiasi codice che avvii una connessione SSL / TLS in uscita.
Jordan Rieger

23

La risposta di @Eddie Loeffen sembra essere la risposta più popolare a questa domanda, ma ha alcuni effetti negativi a lungo termine. Se si esamina la pagina della documentazione per System.Net.ServicePointManager.SecurityProtocol qui, la sezione dei commenti implica che la fase di negoziazione dovrebbe solo risolvere questo problema (e forzare il protocollo è una cattiva pratica perché in futuro anche TLS 1.2 sarà compromesso). Tuttavia, non cercheremmo questa risposta se lo facesse.

Dalla ricerca, sembra che il protocollo di negoziazione ALPN sia necessario per arrivare a TLS1.2 nella fase di negoziazione. Lo abbiamo preso come punto di partenza e abbiamo provato le versioni più recenti del framework .Net per vedere da dove inizia il supporto. Abbiamo scoperto che .Net 4.5.2 non supporta la negoziazione a TLS 1.2, ma .Net 4.6 lo fa.

Quindi, anche se la forzatura di TLS1.2 porterà a termine il lavoro ora, ti consiglio invece di eseguire l'aggiornamento a .Net 4.6. Poiché si tratta di un problema PCI DSS per giugno 2016, la finestra è breve, ma il nuovo framework è una risposta migliore.

AGGIORNAMENTO: Lavorando dai commenti, ho creato questo:

ServicePointManager.SecurityProtocol = 0;    
foreach (SecurityProtocolType protocol in SecurityProtocolType.GetValues(typeof(SecurityProtocolType)))
    {
        switch (protocol)
        {
            case SecurityProtocolType.Ssl3:
            case SecurityProtocolType.Tls:
            case SecurityProtocolType.Tls11:
                break;
            default:
                ServicePointManager.SecurityProtocol |= protocol;
            break;
        }
    }

Per convalidare il concetto, ho combinato SSL3 e TLS1.2 e ho eseguito il codice indirizzato a un server che supporta solo TLS 1.0 e TLS 1.2 (1.1 è disabilitato). Con i protocolli or'd, sembra connettersi bene. Se cambio a SSL3 e TLS 1.1, non è riuscito a connettersi. La mia convalida utilizza HttpWebRequest da System.Net e chiama solo GetResponse (). Ad esempio, ho provato questo e ho fallito:

        HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls11;
        request.GetResponse();

mentre questo ha funzionato:

        HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
        request.GetResponse();

Questo ha un vantaggio rispetto alla forzatura di TLS 1.2 in quanto, se il framework .Net viene aggiornato in modo che ci siano più voci in Enum, saranno supportate dal codice così com'è. Ha uno svantaggio rispetto al solo utilizzo di .Net 4.6 in quanto 4.6 utilizza ALPN e dovrebbe supportare nuovi protocolli se non viene specificata alcuna restrizione.

Modifica 29/4/2019 - Microsoft ha pubblicato questo articolo lo scorso ottobre. Ha una buona sinossi della loro raccomandazione su come questo dovrebbe essere fatto nelle varie versioni di .net framework.


3
Interessante. Sembra che la pagina della documentazione sia stata aggiornata insieme al passaggio di MSDN a ".NET Framework (versione corrente) " e ora spiega che "non è elencato alcun valore predefinito per questa proprietà, apposta". Forse una versione più a prova di futuro della risposta accettata sarebbe quella di interrogare prima la proprietà per recuperare l'elenco dei protocolli consentiti, quindi rimuovere quelli che la tua app considera non sicuri (ovvero qualcosa di meno di TLS 1.2) piuttosto che aggiungere esplicitamente solo il quelli che ritieni sicuri. Ciò non escluderebbe nuove versioni in futuro.
Jordan Rieger

Sarebbe bello poter fare in modo che il programma rimuova i protocolli da un elenco generato dal sistema, ma non vedo un modo per farlo nell'API corrente. L'unica opzione sembra essere quella di forzare il protocollo specifico, cosa che non vedo perché qualcuno vorrebbe fare. Sfortunatamente, senza il supporto ALPN, sembra essere l'unico modo per far funzionare una connessione TLS1.2.
Prof Von Lemongargle

1
Dovrebbe essere possibile eseguire il ciclo di tutte le enumerazioni SecurityProtocolType, vedere quali sono presenti nell'enumerazione dei flag ServicePointManager.SecurityProtocol (è un OR logico di tutti i flag impostati, quindi puoi testarli ciascuno con un AND), quindi creane uno nuovo elenca quelli che non desideri vengano rimossi. Quindi combinali in un enum e imposta la proprietà con quello.
Jordan Rieger

Stavo solo rileggendo il tuo codice enum / looping e penso che non sia corretto. L'operatore logico | = risulterà nella proprietà includendo tutti i valori predefiniti impostati inizialmente nella proprietà, piuttosto che includere solo Tls12 e versioni successive. Per risolverlo, è necessario inizializzare una variabile enum SecurityProtocolType con un valore di 0, eseguire il ciclo | = su tale variabile e quindi assegnarlo alla proprietà ServicePointManager.SecurityProtocol in seguito.
Jordan Rieger

7
Qualcun altro trova folle che .NET non negozi automaticamente la versione del protocollo più alta di cui è capace ?!
Raman

5

@watson

Su Windows Form è disponibile, all'inizio della classe put

  static void Main(string[] args)
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
       //other stuff here
    }

poiché Windows è a thread singolo, è tutto ciò di cui hai bisogno, nel caso in cui sia un servizio devi metterlo proprio sopra la chiamata al servizio (poiché non si può dire su quale thread ti troverai).

using System.Security.Principal 

è anche necessario.


5

Se sei curioso di sapere quali protocolli .NET supporta, puoi provare HttpClient su https://www.howsmyssl.com/

// set proxy if you need to
// WebRequest.DefaultWebProxy = new WebProxy("http://localhost:3128");

File.WriteAllText("howsmyssl-httpclient.html", new HttpClient().GetStringAsync("https://www.howsmyssl.com").Result);

// alternative using WebClient for older framework versions
// new WebClient().DownloadFile("https://www.howsmyssl.com/", "howsmyssl-webclient.html");

Il risultato è schiacciante:

Il tuo client utilizza TLS 1.0, che è molto vecchio, probabilmente suscettibile all'attacco BEAST, e non dispone delle migliori suite di cifratura disponibili. Aggiunte come AES-GCM e SHA256 per sostituire MD5-SHA-1 non sono disponibili per un client TLS 1.0 così come per molte suite di cifratura più moderne.

Come spiega Eddie sopra, puoi abilitare manualmente protocolli migliori:

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

Non so perché utilizzi protocolli sbagliati fuori dagli schemi. Sembra una scelta di configurazione scadente, equivalente a un grave bug di sicurezza (scommetto che molte applicazioni non cambiano l'impostazione predefinita). Come segnalarlo?


5

Ho dovuto lanciare l'equivalente intero per aggirare il fatto che sto ancora utilizzando .NET 4.0

System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
/* Note the property type  
   [System.Flags]
   public enum SecurityProtocolType
   {
     Ssl3 = 48,
     Tls = 192,
     Tls11 = 768,
     Tls12 = 3072,
   } 
*/

Funziona ma .NET 4.0 non supporta TLS 1.2, tuttavia .NET 4.5 e versioni successive supportano TLS 1.2. Quindi puoi aggiungere questo codice (o aggiungere un OR bit per bit per aggiungere il supporto per la negoziazione TLS 1.2) alla tua applicazione .NET 4.0 e compilarlo, ma dovrai distribuire il codice su .NET 4.5 o versioni successive. blogs.perficient.com/microsoft/2016/04/tsl-1-2-and-net-support
rboy

Inoltre vedere questo, il codice NET 4.0 funziona bene su una maggiore versione di .NET compreso .NET 4.5 e .NET 4.6 stackoverflow.com/questions/33378902/...
rboy

Il cast intero ha funzionato per l'invio di TLS 1.2. Il valore dell'enumerazione Tls12 semplicemente non esiste in. NET 4.0
CZahrobsky

Due punti diversi. Vedi il mio commento. Puoi inserire il valore, ma se la tua versione di runtime Net è 4.0 non funzionerà. È possibile compilare con questo flag ma le versioni .NET di runtime devono essere 4.5 o successive poiché i componenti di base su .NET 4.0 non supportano le crittografie richieste per TLS 1.2 (vedere i collegamenti)
rboy

2
Sono disponibili diversi hotfix per le versioni precedenti del runtime .NET per aggiungere il supporto TLS 1.2. es. support.microsoft.com/en-us/help/3154518/… , CZahrobsky avrebbe potuto usarlo anche nell'aggiornamento autunnale dei creatori di Win10 che includeva anche l'hotfix.
tono silenzioso

1

Ho trovato che la soluzione più semplice è aggiungere due voci di registro come segue (eseguilo in un prompt dei comandi con privilegi di amministratore):

reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:32

reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:64

Queste voci sembrano influenzare il modo in cui .NET CLR sceglie un protocollo quando effettua una connessione sicura come client.

Ulteriori informazioni su questa voce di registro sono disponibili qui:

https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2015/2960358#suggested-actions

Non solo è più semplice, ma supponendo che funzioni per il tuo caso, molto più robusto di una soluzione basata su codice, che richiede agli sviluppatori di monitorare il protocollo e lo sviluppo e aggiornare tutto il loro codice pertinente. Si spera che modifiche all'ambiente simili possano essere apportate per TLS 1.3 e versioni successive, a condizione che .NET rimanga abbastanza stupido da non scegliere automaticamente il protocollo più alto disponibile.

NOTA : anche se, secondo l'articolo sopra, questo dovrebbe solo disabilitare RC4 e non si penserebbe che questo cambierebbe se il client .NET è autorizzato a utilizzare TLS1.2 + o meno, per qualche motivo lo ha effetto.

NOTA : come notato da @Jordan Rieger nei commenti, questa non è una soluzione per POODLE, poiché non disabilita i protocolli meno recenti a: consente semplicemente al client di lavorare con i protocolli più recenti, ad esempio quando un server con patch ha disabilitato il vecchio protocolli. Tuttavia, con un attacco MITM, ovviamente un server compromesso offrirà al client un protocollo precedente, che il client utilizzerà quindi felicemente.

TODO : Prova a disabilitare l'uso lato client di TLS1.0 e TLS1.1 con queste voci di registro, tuttavia non so se le librerie client HTTP .NET rispettano queste impostazioni o meno:

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-10

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-11


Le impostazioni del Registro di sistema come alternativa a un codice sarebbero ottime, ma queste impostazioni disabilitano effettivamente TLS 1.0 e 1.1 a favore di consentire solo le connessioni client utilizzando TLS 1.2 e versioni successive? Secondo il link, sembra disabilitare solo RC4 in TLS. Penso che l'attacco del barboncino sia più ampio di quello.
Jordan Rieger

@JordanRieger Queste voci di registro consentono a un client .NET di connettersi a un server che ha i protocolli precedenti disabilitati per mitigare POODLE. Senza questi, il client genererà un errore poiché il client .NET insiste stupidamente sull'utilizzo di un protocollo precedente anche quando il server ne richiede uno più recente. Tutte le scommesse sono disattivate se il tuo server consente ancora le connessioni utilizzando i protocolli precedenti. Teoricamente i protocolli più vecchi dovrebbero essere disabilitati. Mi chiedo se le stesse voci di registro che consentono di disabilitarle sul server (es. Nartac.com/Products/IISCrypto ) funzionerebbero anche per il client?
Raman

Nelle voci di registro manipolate da nartac, ci sono impostazioni separate per (quando agisce come) client e (quando agisce come) server. Non ricordo se la loro interfaccia si distingue comunque. Sai quali versioni di .net supportano questo hack del registro?
Prof Von Lemongargle

@Raman, il punto della mia domanda, tuttavia, era mitigare la vulnerabilità POODLE quando il tuo client si connette a un server che non controlli. La vulnerabilità consentirà a un utente malintenzionato MITM di eseguire il downgrade del protocollo a una versione TLS o SSL precedente che può essere compromessa. La semplice disabilitazione di RC4 non è sufficiente. Queste impostazioni del registro potrebbero essere utili per alcuni casi, ma non lo scenario nella mia domanda.
Jordan Rieger

1
@JordanRieger d'accordo. Ho aggiornato il testo con alcune osservazioni e pensieri aggiuntivi.
Raman
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.