如何在.NET中禁用SSL回退并仅使用TLS进行出站连接? (贵宾犬缓解)

时间:2014-10-15 18:48:27

标签: .net ssl

我正在努力减轻Poodle SSL 3.0 Fallback攻击的漏洞。我们的管理员已经开始禁用SSL,转而使用TLS进行服务器的入站连接。我们还建议我们的团队在其Web浏览器中禁用SSL。我现在正在查看我们的.NET代码库,它通过System.Net.HttpWebRequest启动与各种服务的HTTPS连接。我相信如果这些连接允许从TLS回退到SSL,则它们可能容易受到MITM攻击。这是我到目前为止所确定的。有人可以仔细检查一下以确认我是对的吗?这个漏洞是全新的,所以我还没有看到微软关于如何在.NET中缓解它的任何指导:

  1. 通过 System.Net.ServicePointManager.SecurityProtocol 为每个AppDomain全局设置System.Net.Security.SslStream类的允许协议,该类支持.NET中的安全通信。属性。

  2. .NET 4.5中此属性的默认值为Ssl3 | Tls(虽然我找不到支持它的文档。)SecurityProtocolType是一个带有Flags属性的枚举,所以它是一个按位< em> OR 这两个值。您可以使用以下代码行在您的环境中进行检查:

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

  3. 在您的应用中启动任何连接之前,应将其更改为TlsTls12

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

  4. 重要事项:由于该属性支持多个按位标志,因此我假设SslStream在握手期间会自动回退到其他未指定的协议。否则,支持多个标志会有什么意义?

  5. TLS 1.0与1.1 / 1.2的更新:

    根据Google安全专家Adam Langley的说法TLS 1.0 was later found to be vulnerable to POODLE if not implemented correctly,所以你应该考虑专门转到TLS 1.2。

6 个答案:

答案 0 :(得分:132)

我们正在做同样的事情。要仅支持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

要在IIS中禁用SSL 2.0和3.0,请参阅此页面:https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html

答案 1 :(得分:23)

@Eddie Loeffen的答案似乎是这个问题最受欢迎的答案,但它有一些不良的长期影响。如果您查看System.Net.ServicePointManager.SecurityProtocol here的文档页面,则备注部分意味着协商阶段应该只解决这个问题(强制协议是不好的做法,因为将来,TLS 1.2将被破坏为好)。但是,如果确实如此,我们就不会寻找这个答案。

研究表明,ALPN协商协议在协商阶段需要到达TLS1.2。我们以此为出发点,尝试了.Net框架的新版本,以了解支持的起点。我们发现.Net 4.5.2不支持与TLS 1.2协商,但.Net 4.6不支持协商。

因此,即使强制TLS1.2现在可以完成工作,我建议您升级到.Net 4.6。由于这是2016年6月的PCI DSS问题,因此窗口很短,但新框架是更好的答案。

更新: 根据评论,我建立了这个:

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被禁用)的服务器的代码。使用或者&#39; d协议,似乎连接正常。如果我更改为SSL3和TLS 1.1,则无法连接。我的验证使用来自System.Net的HttpWebRequest,只调用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并且如果没有指定限制则应该支持新协议。

编辑4/29/2019 - 微软去年10月发布了this article。它有一个非常好的概要,他们建议如何在各种版本的.net框架中完成。

答案 2 :(得分:5)

@watson

在Windows窗体上,它可以在类顶部放置

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

因为windows是单线程的,所以你需要它,如果它是一个服务,你需要把它放在服务的调用之上(因为你不知道你将在哪个线程上)。 / p>

using System.Security.Principal 

也是必需的。

答案 3 :(得分:4)

如果您对.NET支持的协议感到好奇,可以在https://www.howsmyssl.com/上尝试HttpClient

// 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攻击,并且没有可用的最佳密码套件。用于替换MD5-SHA-1的AES-GCM和SHA256等附加功能不适用于TLS 1.0客户端以及更多现代密码套件。

正如Eddie上面解释的那样,您可以手动启用更好的协议:

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

我不知道为什么它会使用坏的协议开箱即用。这似乎是一个糟糕的设置选择,相当于一个主要的安全漏洞(我打赌大量的应用程序不会改变默认值)。我们怎么报告呢?

答案 4 :(得分:4)

我必须抛出等价的整数来解决我仍在使用.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,
   } 
*/

答案 5 :(得分:0)

我发现最简单的解决方案是添加两个注册表项,如下所示(在具有管理员权限的命令提示符下运行):

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的解决方案,因为它不会禁用旧协议 - 它只是允许客户端使用更新的协议,例如当修补的服务器禁用旧协议时。然而,在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