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

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

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

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

    еЫпа (System.Net.ServicePointManager.SecurityProtocol.ToString());

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

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

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

Обновление на TLS 1.0 vs 1.1/1.2:

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

Ответ 1

Мы делаем то же самое. Чтобы поддерживать только 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

Ответ 2

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

Исследования показывают, что протокол согласования ALPN требуется для доступа к TLS1.2 на этапе согласования. Мы взяли это за отправную точку и попробовали новые версии .Net Framework, чтобы увидеть, с чего начинается поддержка. Мы обнаружили, что .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 в том, что 4.6 использует ALPN и должен поддерживать новые протоколы, если не указано никаких ограничений.

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

Ответ 3

@watson

В формах окон он доступен, в верхней части класса помещается

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

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

using System.Security.Principal 

также требуется.

Ответ 4

Если вам интересно, какие протоколы поддерживают .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,
   } 
*/

Ответ 6

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

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, очевидно, что скомпрометированный сервер предложит клиенту более старый протокол, который клиент будет с радостью использовать.

TODO: попробуйте отключить использование TLS1.0 и TLS1.1 на стороне клиента с этими записями реестра, однако я не знаю, соблюдают ли эти клиентские библиотеки.NET http эти настройки или нет:

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