Wyłączyć rezerwę SSL i używać tylko TLS dla połączeń wychodzących w .NET? (Łagodzenie skutków Pudla)

106

Próbuję złagodzić naszą lukę w ataku Poodle SSL 3.0 Fallback . Nasi administratorzy już zaczęli wyłączać SSL na rzecz TLS dla połączeń przychodzących do naszych serwerów. Poradziliśmy również naszemu zespołowi, aby wyłączył SSL w swoich przeglądarkach internetowych. Patrzę teraz na naszą bazę kodu .NET, która inicjuje połączenia HTTPS z różnymi usługami za pośrednictwem System.Net.HttpWebRequest . Uważam, że te połączenia mogą być podatne na atak MITM, jeśli pozwolą na powrót z TLS do SSL. Oto, co do tej pory ustaliłem. Czy ktoś mógłby to sprawdzić dwukrotnie, aby potwierdzić, że mam rację? Ta luka jest zupełnie nowa, więc nie widziałem jeszcze żadnych wskazówek od firmy Microsoft, jak ją złagodzić w .NET:

  1. Dozwolone protokoły dla klasy System.Net.Security.SslStream, która stanowi podstawę bezpiecznej komunikacji w .NET, są ustawiane globalnie dla każdej domeny AppDomain za pośrednictwem System.Net.ServicePointManager.SecurityProtocol właściwości .

  2. Domyślną wartością tej właściwości w .NET 4.5 jest Ssl3 | Tls(chociaż nie mogę znaleźć dokumentacji, która by to potwierdzała). SecurityProtocolType to wyliczenie z atrybutem Flags, więc jest to bitowe LUB z tych dwóch wartości. Możesz to sprawdzić w swoim środowisku za pomocą tego wiersza kodu:

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

  3. Należy to zmienić na sprawiedliwe Tls, a możeTls12 przed zainicjowaniem jakichkolwiek połączeń w aplikacji:

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

  4. Ważne: ponieważ właściwość obsługuje wiele flag bitowych, zakładam, że SslStream nie będzie automatycznie wracać do innych nieokreślonych protokołów podczas uzgadniania. W przeciwnym razie jaki byłby sens obsługi wielu flag?

Aktualizacja TLS 1.0 w porównaniu z 1.1 / 1.2:

Według eksperta Google ds. Bezpieczeństwa Adama Langleya, protokół TLS 1.0 okazał się później podatny na działanie POODLE, jeśli nie został prawidłowo zaimplementowany , dlatego należy rozważyć przejście wyłącznie na TLS 1.2.

Aktualizacja dla .NET Framework 4.7 i nowszych:

Jak wspomniał prof Von Lemongargle poniżej, począwszy od wersji 4.7 .NET Framework, nie ma potrzeby używania tego hacka, ponieważ domyślne ustawienie pozwoli systemowi operacyjnemu wybrać najbezpieczniejszą wersję protokołu TLS. Aby uzyskać więcej informacji, zobacz Najważniejsze wskazówki dotyczące zabezpieczeń warstwy transportu (TLS) w programie .NET Framework .

Jordan Rieger
źródło
1
Odnośnie punktu 2 powyżej: patrz referenceource.microsoft.com/#System/net/System/Net/… SslProtocols "Default = Ssl3 | Tls"
Dai Bok
1
@Dai Bok Domyślną teraz jest opcja SystemDefault docs.microsoft.com/en-us/dotnet/api/…
MarwaAhmad
@MarwaAhmad Jeśli tak jest, odwołanie do kodu źródłowego w moim linku nie odzwierciedla wartości domyślnej (48 | 192). Jeśli ustawione na none (0), powinno powrócić do domyślnych ustawień systemowych. To pachnie dla mnie i prawdopodobnie przetestowałbym to przed wprowadzeniem zmian, ponieważ może to doprowadzić do błędnej konfiguracji ... i wyłączenia protokołów na złym frameworku .net ...
Dai Bok

Odpowiedzi:

137

Robimy to samo. Aby obsługiwać tylko protokoły TLS 1.2 i żadnych protokołów SSL, możesz to zrobić:

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

SecurityProtocolType.Tls to tylko protokół TLS 1.0, a nie wszystkie wersje TLS.

Na marginesie: jeśli chcesz sprawdzić, czy Twoja witryna nie zezwala na połączenia SSL, możesz to zrobić tutaj (nie sądzę, aby miało to wpływ na powyższe ustawienie, musieliśmy edytować rejestr, aby zmusić IIS do korzystania z TLS dla połączeń przychodzących): https://www.ssllabs.com/ssltest/index.html

Aby wyłączyć SSL 2.0 i 3.0 w IIS, zobacz tę stronę: https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html

Eddie Fletcher
źródło
Dobrze. Dobry pomysł na obsługę nowszych wersji TLS: zabezpieczenie przyszłości.
Jordan Rieger
1
Z korzyścią dla innych wspomnianą edycję rejestru można również przeprowadzić, wykonując następujące czynności: serverfault.com/a/637263/98656 . W systemie Windows Server 2003 do 2012 R2 protokoły są kontrolowane przez flagi w HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ Schannel \ Protocols. Aby wyłączyć SSLv3, utwórz podklucz w powyższej lokalizacji o nazwie „SSL 3.0”, a pod nim podklucz o nazwie „Serwer”, a pod nim wartość DWORD o nazwie „Włączone”, ustawioną na 0. Powinieneś także wyłączyć SSL 2.0 w ten sam sposób.
Jordan Rieger,
4
@ScotterMonkey Musisz ustawić System.Net.ServicePointManager.SecurityProtocol tylko wtedy, gdy inicjujesz połączenia wychodzące z kodu .NET, np. Łączysz się z usługą internetową lub API z niestandardowego kodu działającego na serwerze. Jeśli masz tylko prostą witrynę internetową i akceptujesz tylko połączenia przychodzące z przeglądarek, wystarczy naprawić rejestr.
Jordan Rieger
7
Uwaga: pojawia się, SecurityProtocolType.Tls11a SecurityProtocolType.Tls12wartości wyliczenia są dostępne tylko w ASP.net 4.5 i nowszych. Nie jestem pewien, co musielibyśmy zrobić dla starszych baz kodu działających w wersji 2.0, gdyby TLS 1.0 zniknął.
Sam
1
@AnishV Umieszczasz ten wiersz kodu podczas inicjalizacji aplikacji, przed jakimkolwiek kodem inicjującym wychodzące połączenie SSL / TLS.
Jordan Rieger,
23

Odpowiedź @Eddie Loeffen wydaje się być najpopularniejszą odpowiedzią na to pytanie, ale ma ona złe długoterminowe skutki. Jeśli przejrzysz stronę z dokumentacją dotyczącą System.Net.ServicePointManager.SecurityProtocol tutaj sekcja uwag sugeruje, że faza negocjacji powinna po prostu rozwiązać ten problem (a wymuszenie protokołu jest złą praktyką, ponieważ w przyszłości TLS 1.2 również zostanie naruszony). Jednak nie szukalibyśmy tej odpowiedzi, gdyby tak było.

Z badań wynika, że ​​protokół negocjacyjny ALPN jest wymagany, aby dostać się do TLS1.2 w fazie negocjacji. Wzięliśmy to za punkt wyjścia i wypróbowaliśmy nowsze wersje frameworka .Net, aby zobaczyć, gdzie zaczyna się wsparcie. Okazało się, że .Net 4.5.2 nie obsługuje negocjacji z TLS 1.2, ale .Net 4.6 obsługuje.

Tak więc, mimo że wymuszenie TLS1.2 wykona zadanie teraz, zalecam zamiast tego aktualizację do .Net 4.6. Ponieważ jest to kwestia PCI DSS w czerwcu 2016 r., Okno jest krótkie, ale nowa struktura jest lepszą odpowiedzią.

UPDATE: Pracując na podstawie komentarzy, zbudowałem to:

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

Aby zweryfikować koncepcję, zdecydowałem się połączyć SSL3 i TLS1.2 i uruchomiłem kod skierowany na serwer, który obsługuje tylko TLS 1.0 i TLS 1.2 (1.1 jest wyłączony). Z protokołami or'd wydaje się, że łączy się dobrze. Jeśli zmienię na SSL3 i TLS 1.1, połączenie nie powiodło się. Moja walidacja używa HttpWebRequest z System.Net i po prostu wywołuje GetResponse (). Na przykład próbowałem tego i nie udało mi się:

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

podczas gdy to działało:

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

Ma to przewagę nad wymuszeniem TLS 1.2, ponieważ jeśli struktura .Net zostanie zaktualizowana, tak aby w Enum było więcej wpisów, będą one obsługiwane przez kod bez zmian. Ma tę wadę w stosunku do samego używania .Net 4.6, ponieważ 4.6 używa ALPN i powinien obsługiwać nowe protokoły, jeśli nie określono żadnych ograniczeń.

Edycja 29.04.2019 - Microsoft opublikował ten artykuł w październiku ubiegłego roku. Zawiera całkiem dobre streszczenie ich zaleceń, jak należy to zrobić w różnych wersjach frameworka .net.

Prof Von Lemongargle
źródło
3
Ciekawy. Wygląda na to, że strona dokumentacji została zaktualizowana wraz z przeniesieniem MSDN do „.NET Framework (aktualna wersja) ”, a teraz wyjaśniono, że „celowo nie podano wartości domyślnej dla tej właściwości”. Być może bardziej przyszłościową wersją zaakceptowanej odpowiedzi byłoby zapytanie właściwości w celu pobrania listy dozwolonych protokołów, a następnie usunięcie tych, które aplikacja uważa za niezabezpieczone (tj. Cokolwiek mniejszego niż TLS 1.2), zamiast jawnego dodawania tylko takie, które uznasz za bezpieczne. Nie wykluczałoby to nowych wersji w przyszłości.
Jordan Rieger,
Byłoby dobrze, gdyby program mógł usuwać protokoły z listy generowanej przez system, ale nie widzę sposobu, aby to zrobić w obecnym API. Wydaje się, że jedyną opcją jest wymuszenie określonego protokołu, czego nie widzę, dlaczego ktokolwiek miałby chcieć to zrobić. Niestety, bez obsługi ALPN wydaje się, że jest to jedyny sposób, aby połączenie TLS1.2 działało.
Prof Von Lemongargle,
1
Powinno być możliwe przejście przez wszystkie wyliczenia SecurityProtocolType, zobaczenie, które z nich są obecne w wyliczeniu flag ServicePointManager.SecurityProtocol (jest to logiczne LUB wszystkich ustawionych flag, więc można przetestować każdą z nich za pomocą AND), a następnie zbudować nową lista z tymi, których nie chcesz usunąć. Następnie połącz je w jedno wyliczenie i ustaw właściwość z tym.
Jordan Rieger,
Właśnie ponownie odczytywałem Twój kod wyliczenia / pętli i myślę, że jest nieprawidłowy. Operator logiczny | = spowoduje, że właściwość będzie zawierała wszelkie wartości domyślne ustawione we właściwości początkowo, a nie tylko Tls12 i nowsze. Aby to naprawić, należy zainicjować zmienną wyliczeniową SecurityProtocolType o wartości 0, wykonać pętlę | = względem tej zmiennej, a następnie przypisać ją do właściwości ServicePointManager.SecurityProtocol.
Jordan Rieger,
7
Czy ktoś inny uważa za szalone, że .NET nie negocjuje automatycznie najwyższej wersji protokołu, do jakiej jest zdolny ?!
Raman
5

@watson

W formularzach okien jest dostępny, na górze klasy należy umieścić

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

ponieważ okna są jednowątkowe, to wszystko, czego potrzebujesz, w przypadku, gdy jest to usługa, musisz umieścić ją tuż nad wywołaniem usługi (ponieważ nie wiadomo, w którym wątku będziesz).

using System.Security.Principal 

jest również potrzebne.

DirtyHowi
źródło
5

Jeśli jesteś ciekawy, które protokoły obsługuje .NET, możesz wypróbować HttpClient na 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");

Rezultat jest potępiający:

Twój klient używa protokołu TLS 1.0, który jest bardzo stary, prawdopodobnie podatny na atak BEAST i nie ma najlepszych dostępnych zestawów szyfrów. Dodatki, takie jak AES-GCM i SHA256 zastępujące MD5-SHA-1, są niedostępne dla klienta TLS 1.0, a także dla wielu innych nowoczesnych zestawów szyfrów.

Jak wyjaśnia Eddie powyżej, możesz ręcznie włączyć lepsze protokoły:

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

Nie wiem, dlaczego po wyjęciu z pudełka używa złych protokołów. Wydaje się, że to kiepski wybór konfiguracji, równoznaczny z poważnym błędem bezpieczeństwa (założę się, że wiele aplikacji nie zmienia ustawień domyślnych). Jak możemy to zgłosić?

Colonel Panic
źródło
5

Musiałem rzucić liczbę całkowitą, aby obejść fakt, że nadal używam .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
źródło
To działa, ale .NET 4.0 nie obsługuje TLS 1.2, jednak .NET 4.5 i nowsze obsługują TLS 1.2. Możesz więc dodać ten kod (lub dodać bitowe OR, aby dodać obsługę negocjacji TLS 1.2) do swojej aplikacji .NET 4.0 i skompilować ją, ale będziesz musiał wdrożyć kod na .NET 4.5 lub nowszym. blogs.perficient.com/microsoft/2016/04/tsl-1-2-and-net-support
rboy
Zobacz też, kod .NET 4.0 będzie działał dobrze w wyższych wersjach .NET, w tym .NET 4.5 i .NET 4.6 stackoverflow.com/questions/33378902/ ...
rboy
Rzutowanie liczb całkowitych działało przy wysyłaniu protokołu TLS 1.2. Wartość wyliczenia Tls12 po prostu nie istnieje w .NET 4.0
CZahrobsky,
Dwie różne kwestie. Zobacz mój komentarz. Możesz podać tę wartość, ale jeśli twoja wersja Runtime Net to 4.0, zakończy się niepowodzeniem. Możesz kompilować z tą flagą, ale twoje wersje środowiska uruchomieniowego .NET muszą być w wersji 4.5 lub wyższej, ponieważ podstawowe komponenty na .NET 4.0 nie obsługują szyfrów wymaganych dla TLS 1.2 (zobacz linki)
rboy,
2
Istnieje kilka poprawek dla starszych wersji środowiska uruchomieniowego .NET, które dodają obsługę TLS 1.2. np. support.microsoft.com/en-us/help/3154518/… , CZahrobsky mógł również użyć tego w jesiennej aktualizacji twórców Win10, która również zawierała poprawkę.
cichy ton
1

Odkryłem, że najprostszym rozwiązaniem jest dodanie dwóch wpisów rejestru w następujący sposób (uruchom to w wierszu polecenia z uprawnieniami administratora):

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

Wydaje się, że wpisy te wpływają na sposób, w jaki środowisko .NET CLR wybiera protokół podczas nawiązywania bezpiecznego połączenia jako klient.

Więcej informacji na temat tego wpisu rejestru można znaleźć tutaj:

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

Jest to nie tylko prostsze, ale zakładając, że działa w Twoim przypadku, znacznie bardziej niezawodne niż rozwiązanie oparte na kodzie, które wymaga od programistów śledzenia protokołu i rozwoju oraz aktualizowania całego odpowiedniego kodu. Miejmy nadzieję, że podobne zmiany w środowisku można wprowadzić dla protokołu TLS 1.3 i nowszych, o ile .NET pozostanie na tyle głupi, aby nie wybierać automatycznie najwyższego dostępnego protokołu.

UWAGA : Mimo że, zgodnie z powyższym artykułem, ma to tylko wyłączyć RC4 i nie można by pomyśleć, że zmieni to, czy klient .NET może używać TLS1.2 +, czy nie, z jakiegoś powodu ma to efekt.

UWAGA : Jak zauważył @Jordan Rieger w komentarzach, nie jest to rozwiązanie dla POODLE, ponieważ nie wyłącza starszych protokołów a - pozwala jedynie klientowi pracować z nowszymi protokołami, np. Gdy załatany serwer wyłączył starszy protokoły. Jednak w przypadku ataku MITM, oczywiście zagrożony serwer zaoferuje klientowi starszy protokół, z którego klient będzie wtedy chętnie korzystał.

TODO : Spróbuj wyłączyć używanie TLS1.0 i TLS1.1 po stronie klienta z tymi wpisami rejestru, jednak nie wiem, czy biblioteki klienta http .NET przestrzegają tych ustawień, czy nie:

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

Ramana
źródło
Ustawienia rejestru jako alternatywa dla kodu byłyby świetne, ale czy te ustawienia faktycznie wyłączają TLS 1.0 i 1.1 na korzyść zezwalania tylko na połączenia klientów przy użyciu TLS 1.2 i nowszych? Zgodnie z linkiem wydaje się, że wyłącza RC4 tylko w TLS. Myślę, że atak Pudla jest szerszy.
Jordan Rieger
@JordanRieger Te wpisy rejestru umożliwiają klientowi .NET łączenie się z serwerem, na którym wyłączono starsze protokoły, aby ograniczyć działanie POODLE. Bez tego klient zgłosi błąd, ponieważ klient .NET głupio nalega na używanie starszego protokołu, nawet gdy serwer prosi o nowszy. Wszystkie zakłady są wyłączone, jeśli serwer nadal umożliwia połączenia przy użyciu starszych protokołów. Teoretycznie starsze protokoły powinny być wyłączone. Zastanawiam się, czy te same wpisy rejestru, które pozwalają na ich wyłączenie na serwerze (np. Nartac.com/Products/IISCrypto ) działałyby również dla klienta?
Raman,
We wpisach rejestru, którymi manipuluje nartac, istnieją oddzielne ustawienia dla (działającego jako) klienta i (działającego jako) serwer. Nie pamiętam, czy ich interfejs to odróżnia. Czy wiesz, które wersje .net obsługują ten hack do rejestru?
Prof Von Lemongargle
@Raman moim pytaniem było jednak złagodzenie luki POODLE, gdy twój klient łączy się z serwerem, którego nie kontrolujesz. Luka ta pozwoli osobie atakującej MITM na obniżenie wersji protokołu do starszej wersji TLS lub SSL, którą można zhakować. Samo wyłączenie RC4 nie wystarczy. Te ustawienia rejestru mogą być przydatne w niektórych przypadkach, ale nie w scenariuszu, o którym mowa w moim pytaniu.
Jordan Rieger
1
@JordanRieger Zgoda. Uzupełniłem tekst o dodatkowe spostrzeżenia i przemyślenia.
Raman