Отключить резервный SSL и использовать только TLS для исходящих соединений в .NET? (Смягчение пуделей)


106

Я пытаюсь уменьшить нашу уязвимость к атаке Poodle SSL 3.0 Fallback . Наши администраторы уже начали отключать SSL в пользу TLS для входящих подключений к нашим серверам. И мы также посоветовали нашей команде отключить SSL в своих веб-браузерах. Теперь я смотрю на нашу кодовую базу .NET, которая инициирует HTTPS-соединения с различными службами через System.Net.HttpWebRequest . Я считаю, что эти соединения могут быть уязвимы для атаки MITM, если они позволяют откат с TLS на SSL. Вот что я определил до сих пор. Не мог бы кто-нибудь перепроверить это, чтобы убедиться, что я прав? Эта уязвимость совершенно новая, поэтому мне еще предстоит увидеть какие-либо инструкции от Microsoft по устранению ее в .NET:

  1. Разрешенные протоколы для класса System.Net.Security.SslStream, который поддерживает безопасную связь в .NET, устанавливаются глобально для каждого домена приложения через свойство System.Net.ServicePointManager.SecurityProtocol .

  2. Значение этого свойства по умолчанию в .NET 4.5 равно Ssl3 | Tls(хотя я не могу найти подтверждающую документацию). SecurityProtocolType - это перечисление с атрибутом Flags, так что это побитовое ИЛИ этих двух значений. Вы можете проверить это в своей среде с помощью этой строки кода:

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

  3. Это следует изменить на просто Tlsили, возможно Tls12, до того, как вы инициируете какие-либо подключения в своем приложении:

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

  4. Важное замечание : поскольку свойство поддерживает несколько побитовых флагов, я предполагаю, что SslStream не будет автоматически переходить к другим неуказанным протоколам во время рукопожатия. В противном случае какой смысл поддерживать несколько флагов?

Обновление TLS 1.0 против 1.1 / 1.2:

По словам эксперта по безопасности Google Адама Лэнгли, TLS 1.0 позже оказался уязвимым для POODLE, если не был реализован правильно , поэтому вам следует подумать о переходе исключительно на TLS 1.2.

Обновление для .NET Framework 4.7 и выше:

Как упоминается ниже профессором фон Лемонгарглом , начиная с версии 4.7 .NET Framework, нет необходимости использовать этот хакерский прием, поскольку настройка по умолчанию позволяет ОС выбирать наиболее безопасную версию протокола TLS. Дополнительные сведения см. В разделе « Передовые методы безопасности транспортного уровня (TLS) с .NET Framework» .


1
Что касается пункта 2 выше: см referencesource.microsoft.com/#System/net/System/Net/... SslProtocols " По умолчанию = SSL3 | Tls"
Dai Бок

1
@Dai Bok Теперь по умолчанию используется параметр SystemDefault docs.microsoft.com/en-us/dotnet/api/…
MarwaAhmad,

@MarwaAhmad, если это так, ссылка на исходный код в моей ссылке не отражает значение по умолчанию (48 | 192). Если установлено значение «нет» (0), он должен вернуться к системным значениям по умолчанию. Мне это неприятно, и я бы, вероятно, протестировал это, прежде чем вносить изменения, поскольку это может привести к неправильной конфигурации ... и отключению протоколов на неправильной платформе .net ...
Дай Бок

Ответы:


137

Мы делаем то же самое. Чтобы поддерживать только TLS 1.2 и не использовать протоколы SSL, вы можете сделать следующее:

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

SecurityProtocolType.Tls - это только TLS 1.0, а не все версии TLS.

В качестве стороны: если вы хотите проверить, что ваш сайт не разрешает SSL-соединения, вы можете сделать это здесь (я не думаю, что на это повлияет вышеуказанный параметр, нам пришлось отредактировать реестр, чтобы заставить IIS использовать TLS. для входящих подключений): https://www.ssllabs.com/ssltest/index.html

Чтобы отключить SSL 2.0 и 3.0 в IIS, см. Эту страницу: https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html


Правильно. Хорошая идея - поддержать и более новые версии TLS: готовность к будущему.
Jordan Rieger

1
И для других, упомянутое вами редактирование реестра также можно выполнить с помощью следующих шагов: serverfault.com/a/637263/98656 . В Windows Server 2003 до 2012 R2 протоколы контролируются флагами в HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ Schannel \ Protocols. Чтобы отключить SSLv3, создайте подраздел в указанном выше месте с именем «SSL 3.0» и под ним подраздел с именем «Сервер» и под ним значение DWORD с именем «Включено», равное 0. Вам также следует отключить SSL 2.0. таким же образом.
Jordan Rieger

4
@ScotterMonkey Вам нужно установить System.Net.ServicePointManager.SecurityProtocol только в том случае, если вы инициируете исходящие соединения из кода .NET, например, подключаетесь к веб-службе или API из пользовательского кода, запущенного на вашем сервере. Если у вас только простой веб-сайт и вы принимаете только входящие соединения от браузеров, исправления реестра будет достаточно.
Джордан Ригер,

7
Примечание. Появляется, SecurityProtocolType.Tls11и SecurityProtocolType.Tls12значения перечисления доступны только в ASP.net 4.5 и выше. Не уверен, что нам нужно сделать для более старых баз кода, работающих на 2.0, если TLS 1.0 уйдет на второй план.
Сэм

1
@AnishV Вы помещаете эту строку кода при инициализации вашего приложения перед любым кодом, который инициирует исходящее соединение SSL / TLS.
Джордан Ригер,

23

Ответ @Eddie Loeffen кажется самым популярным ответом на этот вопрос, но он имеет плохие долгосрочные последствия. Если вы просмотрите страницу документации для System.Net.ServicePointManager.SecurityProtocol здесь, раздел примечаний подразумевает, что фаза согласования должна просто решить эту проблему (и принудительное использование протокола является плохой практикой, потому что в будущем TLS 1.2 также будет скомпрометирован). Однако, если бы это было так, мы бы не стали искать этот ответ.

Исследования показывают, что протокол согласования ALPN необходим для доступа к TLS1.2 на этапе согласования. Мы взяли это за отправную точку и попробовали более новые версии инфраструктуры .Net, чтобы увидеть, где начинается поддержка. Мы обнаружили, что .Net 4.5.2 не поддерживает согласование с TLS 1.2, но .Net 4.6 поддерживает.

Итак, даже если принудительное использование TLS1.2 позволит выполнить свою работу, я рекомендую вам вместо этого перейти на .Net 4.6. Поскольку это проблема PCI DSS на июнь 2016 года, окно короткое, но новая структура - лучший ответ.

ОБНОВЛЕНИЕ: Работая по комментариям, я построил это:

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

Чтобы проверить концепцию, я объединил SSL3 и TLS1.2 и запустил код, ориентированный на сервер, который поддерживает только TLS 1.0 и TLS 1.2 (1.1 отключен). С протоколами or'd вроде нормально подключается. Если я перейду на SSL3 и TLS 1.1, мне не удастся подключиться. Моя проверка использует HttpWebRequest из System.Net и просто вызывает GetResponse (). Например, я попробовал это и не смог:

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

пока это работало:

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

Это имеет преимущество перед принудительным использованием TLS 1.2 в том, что если инфраструктура .Net обновлена ​​так, чтобы в Enum было больше записей, они будут поддерживаться кодом как есть. У него есть недостаток по сравнению с использованием .Net 4.6, поскольку он использует ALPN и должен поддерживать новые протоколы, если не указано никаких ограничений.

Изменить 29.04.2019 - Microsoft опубликовала эту статью в октябре прошлого года. В нем есть довольно хорошее резюме их рекомендаций о том, как это должно быть сделано в различных версиях .NET Framework.


3
Интересный. Похоже, что страница документации была обновлена ​​вместе с переходом MSDN на «.NET Framework (текущая версия) », и теперь объясняется, что «для этого свойства специально не указано значение по умолчанию». Возможно, более перспективной версией принятого ответа было бы сначала запросить свойство, чтобы получить список разрешенных протоколов, а затем удалить те, которые ваше приложение считает небезопасными (то есть что-то меньшее, чем TLS 1.2), а не явно добавлять только те, которые вы считаете безопасными. Это не исключает появления новых версий в будущем.
Jordan Rieger

Было бы хорошо, если бы программа могла удалить протоколы из списка, который генерирует система, но я не вижу способа сделать это в текущем API. Кажется, единственный вариант - принудительно установить конкретный протокол, что я не понимаю, зачем кому-то это нужно. К сожалению, без поддержки ALPN это, кажется, единственный способ заставить работать соединение TLS1.2.
Prof Von Lemongargle 09

1
Должна быть возможность перебрать все перечисления SecurityProtocolType, посмотреть, какие из них присутствуют в перечислении флагов ServicePointManager.SecurityProtocol (это логическое ИЛИ всех установленных флагов, поэтому вы можете проверить каждый из них с помощью И), а затем построить новый перечислите их с теми, которые вы не хотите удалять. Затем объедините их в одно перечисление и установите свойство с этим.
Джордан Ригер,

Я просто перечитывал ваш код перечисления / цикла, и я думаю, что это неверно. Логический оператор | = приведет к тому, что свойство будет включать все значения по умолчанию, которые были установлены в свойстве изначально, а не только Tls12 и выше. Чтобы исправить это, вам нужно инициализировать переменную перечисления SecurityProtocolType значением 0, выполнить цикл | = для этой переменной, а затем назначить его свойству ServicePointManager.SecurityProtocol после этого.
Джордан Ригер,

7
Кто-нибудь еще находит безумным, что .NET не согласовывает автоматически самую высокую версию протокола, на которую она способна ?!
Раман

5

@watson

В формах окна это доступно, вверху класса поставьте

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

поскольку окна являются однопоточными, это все, что вам нужно, в случае, если это служба, вам нужно поместить ее прямо над вызовом службы (поскольку неизвестно, в каком потоке вы будете).

using System.Security.Principal 

тоже нужен.


5

Если вам интересно, какие протоколы поддерживает .NET, вы можете попробовать HttpClient на 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");

Результат потрясающий:

Ваш клиент использует TLS 1.0, который очень старый, возможно, восприимчивый к атаке BEAST, и не имеет лучших доступных наборов шифров. Такие дополнения, как AES-GCM и SHA256 для замены MD5-SHA-1, недоступны для клиента TLS 1.0, а также для многих других современных наборов шифров.

Как объясняет Эдди выше, вы можете включить лучшие протоколы вручную:

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

Я не знаю, почему он изначально использует плохие протоколы. Это кажется плохим выбором настройки, равносильно серьезной ошибке безопасности (держу пари, что многие приложения не меняют настройки по умолчанию). Как мы можем сообщить об этом?


5

Мне пришлось преобразовать целочисленный эквивалент, чтобы обойти тот факт, что я все еще использую .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,
   } 
*/

Это работает, но .NET 4.0 не поддерживает TLS 1.2, однако .NET 4.5 и выше поддерживает TLS 1.2. Таким образом, вы можете добавить этот код (или добавить побитовое ИЛИ, чтобы добавить поддержку согласования TLS 1.2) в свое приложение .NET 4.0 и построить его, но вам нужно будет развернуть код на .NET 4.5 или выше. blogs.perficient.com/microsoft/2016/04/tsl-1-2-and-net-support
rboy

Также обратите внимание: код .NET 4.0 будет нормально работать в более
поздних

Целочисленное приведение работало для отправки TLS 1.2. Значение перечисления Tls12 просто не существует в .NET 4.0
Чахробский

Две разные точки. См. Мой комментарий. Вы можете указать значение, но если ваша версия Net Runtime 4.0 - это ошибка. Вы можете компилировать с этим флагом, но ваши версии .NET во время выполнения должны быть 4.5 или выше, поскольку базовые компоненты .NET 4.0 не поддерживают шифров, необходимых для TLS 1.2 (см. Ссылки)
rboy

2
Есть несколько исправлений для более старых версий среды выполнения .NET, чтобы добавить поддержку TLS 1.2. Например, support.microsoft.com/en-us/help/3154518/… , Ч.Захробски мог также использовать это в обновлении создателей падения Win10, которое также включало исправление.
тихий тон

1

Я обнаружил, что самое простое решение - добавить две записи в реестр следующим образом (запустите это в командной строке с правами администратора):

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

Эти записи, похоже, влияют на то, как .NET CLR выбирает протокол при создании безопасного соединения в качестве клиента.

Дополнительная информация об этой записи реестра находится здесь:

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

Это не только проще, но и, если предположить, что это работает в вашем случае, гораздо более надежно, чем решение на основе кода, которое требует от разработчиков отслеживания протокола и разработки и обновления всего соответствующего кода. Будем надеяться, что аналогичные изменения среды могут быть сделаны для TLS 1.3 и более поздних версий, если .NET остается достаточно глупой, чтобы автоматически не выбирать самый высокий доступный протокол.

ПРИМЕЧАНИЕ . Несмотря на то, что, согласно приведенной выше статье, это должно отключать только RC4, и никто бы не подумал, что это изменит, разрешено ли клиенту .NET использовать TLS1.2 + или нет, по какой-то причине у него есть это эффект.

ПРИМЕЧАНИЕ . Как отметил @Jordan Rieger в комментариях, это не решение для POODLE, поскольку оно не отключает старые протоколы a - оно просто позволяет клиенту работать с новыми протоколами, например, когда исправленный сервер отключил старые протоколы. протоколы. Однако при атаке MITM очевидно, что скомпрометированный сервер предложит клиенту более старый протокол, который затем клиент с радостью будет использовать.

ЗАДАЧА : попробуйте отключить использование TLS1.0 и TLS1.1 на стороне клиента с помощью этих записей реестра, однако я не знаю, соблюдают ли клиентские библиотеки .NET эти параметры или нет:

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


Параметры реестра в качестве альтернативы коду были бы хороши, но действительно ли эти настройки отключают TLS 1.0 и 1.1 в пользу разрешения клиентских подключений только с использованием TLS 1.2 и выше? По ссылке вроде отключает только RC4 в TLS. Я думаю, что атака Пуделя шире.
Jordan Rieger

@JordanRieger Эти записи реестра позволяют клиенту .NET подключаться к серверу, на котором старые протоколы отключены для смягчения последствий POODLE. Без них клиент выдаст ошибку, поскольку клиент .NET глупо настаивает на использовании старого протокола, даже когда сервер запрашивает более новый. Все ставки отключены, если ваш сервер по-прежнему разрешает соединения с использованием старых протоколов. Теоретически старые протоколы следует отключить. Интересно, подойдут ли те же записи реестра, которые позволяют отключать их на сервере (например, nartac.com/Products/IISCrypto ) и для клиента?
Раман

В записях реестра, которыми манипулирует nartac, есть отдельные настройки для (когда он действует как) клиента и (когда действует как) сервера. Однако я не помню, отличается ли их интерфейс. Вы знаете, какие версии .net поддерживают этот взлом реестра?
Prof Von Lemongargle

@Raman, однако, мой вопрос был в том, чтобы уменьшить уязвимость POODLE, когда ваш клиент подключается к серверу, который вы не контролируете. Уязвимость позволит злоумышленнику MITM понизить версию протокола до более старой версии TLS или SSL, которая может быть взломана. Недостаточно просто отключить RC4. Эти параметры реестра могут быть полезны в определенных случаях, но не в моем вопросе.
Jordan Rieger

1
@JordanRieger Согласен. Я обновил текст некоторыми дополнительными наблюдениями и мыслями.
Раман
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.