Désactiver le secours SSL et utiliser uniquement TLS pour les connexions sortantes dans .NET? (Atténuation des caniches)

106

J'essaie d'atténuer notre vulnérabilité à l' attaque de secours Poodle SSL 3.0 . Nos administrateurs ont déjà commencé à désactiver SSL au profit de TLS pour les connexions entrantes vers nos serveurs. Et nous avons également conseillé à notre équipe de désactiver SSL dans leurs navigateurs Web. Je regarde maintenant notre base de code .NET, qui initie des connexions HTTPS avec divers services via System.Net.HttpWebRequest . Je pense que ces connexions pourraient être vulnérables à une attaque MITM si elles permettent le retour de TLS vers SSL. Voici ce que j'ai déterminé jusqu'à présent. Quelqu'un pourrait-il vérifier cela pour vérifier que j'ai raison? Cette vulnérabilité est toute nouvelle, je n'ai donc pas encore vu de conseils de Microsoft sur la façon de l'atténuer dans .NET:

  1. Les protocoles autorisés pour la classe System.Net.Security.SslStream, qui sous-tendent la communication sécurisée dans .NET, sont définis globalement pour chaque AppDomain via la propriété System.Net.ServicePointManager.SecurityProtocol .

  2. La valeur par défaut de cette propriété dans .NET 4.5 est Ssl3 | Tls(bien que je ne trouve pas de documentation pour le sauvegarder.) SecurityProtocolType est une énumération avec l'attribut Flags, donc c'est un OU au niveau du bit de ces deux valeurs. Vous pouvez vérifier cela dans votre environnement avec cette ligne de code:

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

  3. Cela devrait être remplacé par juste Tls, ou peut Tls12- être , avant de lancer des connexions dans votre application:

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

  4. Important: Étant donné que la propriété prend en charge plusieurs indicateurs au niveau du bit, je suppose que SslStream ne se repliera pas automatiquement vers d'autres protocoles non spécifiés pendant la négociation. Sinon, quel serait l'intérêt de supporter plusieurs drapeaux?

Mise à jour sur TLS 1.0 vs 1.1 / 1.2:

Selon l'expert en sécurité de Google, Adam Langley, TLS 1.0 s'est avéré plus tard vulnérable à POODLE s'il n'était pas implémenté correctement , vous devriez donc envisager de passer exclusivement à TLS 1.2.

Mise à jour pour .NET Framework 4.7 et supérieur:

Comme évoqué par le professeur Von Lemongargle ci-dessous, à partir de la version 4.7 du .NET Framework, il n'est pas nécessaire d'utiliser ce hack car le paramètre par défaut permettra au système d'exploitation de choisir la version de protocole TLS la plus sécurisée. Consultez les bonnes pratiques TLS (Transport Layer Security) avec le .NET Framework pour plus d'informations.

Jordan Rieger
la source
1
Concernant le point 2 ci-dessus: voir referencesource.microsoft.com/#System/net/System/Net/… SslProtocols "Default = Ssl3 | Tls"
Dai Bok
1
@Dai Bok La valeur par défaut est désormais l'option SystemDefault docs.microsoft.com/en-us/dotnet/api/…
MarwaAhmad
@MarwaAhmad si tel est le cas, la référence du code source dans mon lien ne reflète pas la valeur par défaut (48 | 192). S'il est défini sur aucun (0), il devrait revenir à la valeur par défaut du système. Cela me sent et je testerais probablement cela avant d'apporter des modifications car cela peut entraîner une mauvaise configuration ... et désactiver les protocoles sur le mauvais framework .net ...
Dai Bok

Réponses:

137

Nous faisons la même chose. Pour prendre en charge uniquement TLS 1.2 et aucun protocole SSL, vous pouvez le faire:

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

SecurityProtocolType.Tls est uniquement TLS 1.0, pas toutes les versions TLS.

En complément: si vous voulez vérifier que votre site n'autorise pas les connexions SSL, vous pouvez le faire ici (je ne pense pas que cela sera affecté par le paramètre ci-dessus, nous avons dû modifier le registre pour forcer IIS à utiliser TLS pour les connexions entrantes): https://www.ssllabs.com/ssltest/index.html

Pour désactiver SSL 2.0 et 3.0 dans IIS, consultez cette page: https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html

Eddie Fletcher
la source
Droite. Bonne idée de prendre également en charge les nouvelles versions de TLS: la pérennité.
Jordan Rieger
1
Et pour le bénéfice des autres, la modification du registre que vous avez mentionnée peut également être effectuée avec ces étapes: serverfault.com/a/637263/98656 . Dans Windows Server 2003 à 2012 R2, les protocoles sont contrôlés par des indicateurs à HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ Schannel \ Protocols. Pour désactiver SSLv3, créez une sous-clé à l'emplacement ci-dessus nommé 'SSL 3.0' et, en dessous, une sous-clé nommée 'Server' et, en dessous, une valeur DWORD nommée 'Enabled', définie sur 0. Vous devez également désactiver SSL 2.0 de la même manière.
Jordan Rieger
4
@ScotterMonkey Vous ne devez définir System.Net.ServicePointManager.SecurityProtocol que si vous lancez des connexions sortantes à partir du code .NET, par exemple en vous connectant à un service Web ou à une API à partir d'un code personnalisé s'exécutant sur votre serveur. Si vous n'exécutez qu'un simple site Web et que vous n'acceptez que les connexions entrantes des navigateurs, le correctif de registre suffit.
Jordan Rieger
7
Remarque: il apparaît SecurityProtocolType.Tls11et les SecurityProtocolType.Tls12valeurs d'énumération ne sont disponibles que dans ASP.net 4.5 et versions ultérieures. Je ne sais pas ce que nous aurions à faire pour les anciennes bases de code fonctionnant sous 2.0 si TLS 1.0 passait au bord du chemin.
Sam
1
@AnishV Vous mettez cette ligne de code dans l'initialisation de votre application, avant tout code qui initie une connexion SSL / TLS sortante.
Jordan Rieger
23

La réponse de @Eddie Loeffen semble être la réponse la plus populaire à cette question, mais elle a de mauvais effets à long terme. Si vous consultez la page de documentation de System.Net.ServicePointManager.SecurityProtocol ici, la section des remarques implique que la phase de négociation devrait simplement résoudre ce problème (et forcer le protocole est une mauvaise pratique car à l'avenir, TLS 1.2 sera également compromis). Cependant, nous ne chercherions pas cette réponse si c'était le cas.

En recherchant, il semble que le protocole de négociation ALPN est nécessaire pour atteindre TLS1.2 dans la phase de négociation. Nous avons pris cela comme point de départ et avons essayé des versions plus récentes du framework .Net pour voir où commence le support. Nous avons constaté que .Net 4.5.2 ne prend pas en charge la négociation vers TLS 1.2, contrairement à .Net 4.6.

Donc, même si forcer TLS1.2 fera le travail maintenant, je vous recommande de mettre à niveau vers .Net 4.6 à la place. Puisqu'il s'agit d'un problème PCI DSS pour juin 2016, la fenêtre est courte, mais le nouveau cadre est une meilleure réponse.

MISE À JOUR: En travaillant à partir des commentaires, j'ai construit ceci:

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

Afin de valider le concept, j'ai associé SSL3 et TLS1.2 et exécuté le code ciblant un serveur qui ne prend en charge que TLS 1.0 et TLS 1.2 (1.1 est désactivé). Avec les protocoles or'd, il semble bien se connecter. Si je passe à SSL3 et TLS 1.1, cela n'a pas pu se connecter. Ma validation utilise HttpWebRequest de System.Net et appelle simplement GetResponse (). Par exemple, j'ai essayé ceci et j'ai échoué:

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

pendant que cela fonctionnait:

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

Cela présente un avantage par rapport au forçage de TLS 1.2 en ce que, si le framework .Net est mis à niveau afin qu'il y ait plus d'entrées dans Enum, elles seront prises en charge par le code tel quel. Il a un inconvénient par rapport à l'utilisation de .Net 4.6 en ce que 4.6 utilise ALPN et devrait prendre en charge de nouveaux protocoles si aucune restriction n'est spécifiée.

Edit 29/04/2019 - Microsoft a publié cet article en octobre dernier. Il a un assez bon résumé de leur recommandation sur la façon dont cela devrait être fait dans les différentes versions du framework .net.

Prof Von Lemongargle
la source
3
Intéressant. Il semble que la page de documentation a été mise à jour avec le passage de MSDN à «.NET Framework (version actuelle) » et explique maintenant que «aucune valeur par défaut n'est répertoriée pour cette propriété, à dessein». Peut-être qu'une version plus pérenne de la réponse acceptée consisterait d'abord à interroger la propriété pour récupérer la liste des protocoles autorisés, puis à supprimer ceux que votre application considère comme non sécurisés (c'est-à-dire tout ce qui est inférieur à TLS 1.2) plutôt que d'ajouter explicitement uniquement le ceux que vous jugez sûrs. Cela n'exclurait pas de nouvelles versions à l'avenir.
Jordan Rieger
Ce serait bien de pouvoir demander au programme de supprimer les protocoles d'une liste générée par le système, mais je ne vois pas de moyen de le faire dans l'API actuelle. La seule option semble être de forcer le protocole spécifique, ce que je ne vois pas pourquoi quiconque voudrait le faire. Malheureusement, sans le support ALPN, cela semble être le seul moyen de faire fonctionner une connexion TLS1.2.
Prof Von Lemongargle
1
Il devrait être possible de parcourir tous les enums SecurityProtocolType, voir lesquels sont présents dans l'énumération des indicateurs ServicePointManager.SecurityProtocol (c'est un OU logique de tous les indicateurs définis, vous pouvez donc tester chacun avec un ET), puis créer un nouveau liste d'entre eux avec ceux que vous ne voulez pas supprimer. Ensuite, combinez-les en une seule énumération et définissez la propriété avec cela.
Jordan Rieger
J'étais juste en train de relire votre code d'énumération / boucle, et je pense que c'est incorrect. L'opérateur logique | = aboutira à ce que la propriété inclue les valeurs par défaut définies initialement dans la propriété, plutôt que d'inclure uniquement Tls12 et supérieur. Pour résoudre ce problème, vous devez initialiser une variable d'énumération SecurityProtocolType avec une valeur de 0, effectuer la boucle | = sur cette variable, puis l'affecter à la propriété ServicePointManager.SecurityProtocol par la suite.
Jordan Rieger
7
Quelqu'un d'autre trouve-t-il insensé que .NET ne négocie pas automatiquement la version de protocole la plus élevée dont il est capable?!
Raman
5

@watson

Sur les formulaires Windows, il est disponible, en haut de la classe mis

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

puisque Windows est à thread unique, c'est tout ce dont vous avez besoin, dans le cas où il s'agit d'un service, vous devez le placer juste au-dessus de l'appel au service (car il est impossible de dire sur quel thread vous serez).

using System.Security.Principal 

est également nécessaire.

DirtyHowi
la source
5

Si vous êtes curieux de savoir quels protocoles .NET prend en charge, vous pouvez essayer HttpClient sur 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");

Le résultat est accablant:

Votre client utilise TLS 1.0, qui est très ancien, peut-être sensible à l'attaque BEAST, et ne dispose pas des meilleures suites de chiffrement disponibles. Les ajouts tels que AES-GCM et SHA256 pour remplacer MD5-SHA-1 ne sont pas disponibles pour un client TLS 1.0 ainsi que pour de nombreuses suites de chiffrement plus modernes.

Comme Eddie l'explique ci-dessus, vous pouvez activer manuellement de meilleurs protocoles:

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

Je ne sais pas pourquoi il utilise de mauvais protocoles prêts à l'emploi. Cela semble un mauvais choix de configuration, ce qui équivaut à un bogue de sécurité majeur (je parie que beaucoup d'applications ne changent pas la valeur par défaut). Comment pouvons-nous le signaler?

Colonel Panic
la source
5

J'ai dû lancer l'équivalent entier pour contourner le fait que j'utilise toujours .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,
   } 
*/
CZahrobsky
la source
Cela fonctionne mais .NET 4.0 ne prend pas en charge TLS 1.2, cependant .NET 4.5 et les versions ultérieures prennent en charge TLS 1.2. Vous pouvez donc ajouter ce code (ou ajouter une opération au niveau du bit OU pour ajouter la prise en charge de la négociation TLS 1.2) à votre application .NET 4.0 et la générer, mais vous devrez déployer le code sur .NET 4.5 ou supérieur. blogs.perficient.com/microsoft/2016/04/tsl-1-2-and-net-support
rboy
Voir également ceci, le code .NET 4.0 fonctionnera correctement sur la version supérieure de .NET, y compris .NET 4.5 et .NET 4.6 stackoverflow.com/questions/33378902/…
rboy
Le cast entier fonctionnait pour l'envoi de TLS 1.2. La valeur d'énumération Tls12 n'existe tout simplement pas dans. NET 4.0
CZahrobsky
Deux points différents. Voir mon commentaire. Vous pouvez mettre la valeur, mais si votre version Net d'exécution est 4.0, elle échouera. Vous pouvez compiler avec cet indicateur, mais vos versions d'exécution .NET doivent être 4.5 ou supérieures car les composants de base sur .NET 4.0 ne prennent pas en charge les chiffrements requis pour TLS 1.2 (voir les liens)
rboy
2
Il existe plusieurs correctifs pour les anciennes versions d'exécution .NET pour ajouter la prise en charge de TLS 1.2. par exemple support.microsoft.com/en-us/help/3154518/… , CZahrobsky aurait pu également l'utiliser sur la mise à jour des créateurs d'automne Win10 qui incluait également le correctif.
ton silencieux
1

J'ai trouvé que la solution la plus simple consiste à ajouter deux entrées de registre comme suit (exécutez ceci dans une invite de commande avec des privilèges d'administrateur):

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

Ces entrées semblent affecter la façon dont le .NET CLR choisit un protocole lors de l'établissement d'une connexion sécurisée en tant que client.

Il y a plus d'informations sur cette entrée de registre ici:

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

Non seulement c'est plus simple, mais en supposant que cela fonctionne pour votre cas, beaucoup plus robuste qu'une solution basée sur du code, qui oblige les développeurs à suivre le protocole et le développement et à mettre à jour tout leur code pertinent. Espérons que des modifications d'environnement similaires peuvent être apportées pour TLS 1.3 et au-delà, tant que .NET reste suffisamment stupide pour ne pas choisir automatiquement le protocole le plus élevé disponible.

REMARQUE : même si, selon l'article ci-dessus, cela est uniquement censé désactiver RC4, et on ne penserait pas que cela changerait si le client .NET est autorisé à utiliser TLS1.2 + ou non, pour une raison quelconque, il l'a effet.

REMARQUE : Comme indiqué par @Jordan Rieger dans les commentaires, ce n'est pas une solution pour POODLE, car il ne désactive pas les anciens protocoles a - il permet simplement au client de travailler avec des protocoles plus récents, par exemple lorsqu'un serveur patché a désactivé l'ancien protocoles. Cependant, avec une attaque MITM, il est évident qu'un serveur compromis offrira au client un protocole plus ancien, que le client utilisera alors avec plaisir.

TODO : Essayez de désactiver l'utilisation côté client de TLS1.0 et TLS1.1 avec ces entrées de registre, mais je ne sais pas si les bibliothèques clientes .NET http respectent ces paramètres ou non:

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

Raman
la source
Les paramètres de registre comme alternative à un code seraient formidables, mais ces paramètres désactivent-ils réellement TLS 1.0 et 1.1 au profit de n'autoriser que les connexions clientes utilisant TLS 1.2 et supérieur? Selon le lien, il semble ne désactiver que RC4 dans TLS. Je pense que l'attaque Poodle est plus large que cela.
Jordan Rieger
@JordanRieger Ces entrées de registre permettent à un client .NET de se connecter à un serveur dont les anciens protocoles sont désactivés pour atténuer POODLE. Sans ceux-ci, le client lancera une erreur car le client .NET insiste bêtement pour utiliser un protocole plus ancien même lorsque le serveur en demande un plus récent. Tous les paris sont désactivés si votre serveur autorise toujours les connexions utilisant les anciens protocoles. Théoriquement, les anciens protocoles devraient être désactivés. Je me demande si les mêmes entrées de registre qui permettent de les désactiver sur le serveur (par exemple nartac.com/Products/IISCrypto ) fonctionneraient aussi pour le client?
Raman le
Dans les entrées de registre que nartac manipule, il existe des paramètres séparés pour (lorsqu'il agit en tant que) client et (lorsqu'il agit en tant que) serveur. Je ne me souviens pas si leur interface se distingue cependant. Savez-vous quelles versions de .net prennent en charge ce piratage de registre?
Prof Von Lemongargle
@Raman le but de ma question, cependant, était d'atténuer la vulnérabilité POODLE lorsque votre client se connecte à un serveur que vous ne contrôlez pas. La vulnérabilité permettra à un attaquant MITM de rétrograder le protocole vers une version plus ancienne de TLS ou SSL qui peut être piratée. Il ne suffit pas de désactiver RC4. Ces paramètres de registre peuvent être utiles dans certains cas, mais pas dans le scénario de ma question.
Jordan Rieger
1
@JordanRieger D'accord. J'ai mis à jour le texte avec quelques observations et réflexions supplémentaires.
Raman