禁用SSL后备,仅将TLS用于.NET中的出站连接?(缓解贵宾犬)


106

我正在尝试减轻我们对Poodle SSL 3.0 Fallback攻击的脆弱性。我们的管理员已经开始禁用TLS,而将TLS禁用为与服务器的入站连接。我们还建议我们的团队在其网络浏览器中禁用SSL。我现在正在看我们的.NET代码库,该代码库通过System.Net.HttpWebRequest启动与各种服务的HTTPS连接。我相信,如果这些连接允许从TLS退回到SSL,则可能会受到MITM攻击。到目前为止,这是我确定的。可以请某人仔细检查一下以确认我是对的吗?该漏洞是全新的,因此我尚未看到Microsoft提供的有关如何在.NET中缓解该漏洞的任何指导:

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

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

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

  3. 在您启动应用程序中的任何连接之前Tls,应将其更改为just ,或者也许是Tls12

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

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

TLS 1.0和1.1 / 1.2的更新:

根据Google安全专家Adam Langley的说法,如果未正确实施TLS 1.0,则以后很容易受到POODLE的攻击,因此您应该考虑专门迁移到TLS 1.2。

.NET Framework 4.7及更高版本的更新:

正如以下Von Lemongargle教授所暗示的那样,从.NET Framework 4.7版开始,无需使用此技巧,因为默认设置将允许操作系统选择最安全的TLS协议版本。有关更多信息,请参见.NET Framework的传输层安全性(TLS)最佳做法


1
关于上述第2点:请参见referencesource.microsoft.com/#System/net/System/Net/…SslProtocols “默认= Ssl3 | Tls”
Dai Bok

1
@Dai博克默认现在是SystemDefault选项docs.microsoft.com/en-us/dotnet/api/...
MarwaAhmad

如果是@MarwaAhmad,则我链接中的源代码引用未反映默认值(48 | 192)。如果设置为none(0),则应恢复为系统默认值。这对我来说很香,我可能会在进行更改之前进行测试,因为这可能会导致配置错误...并在错误的.net框架上关闭协议...
Dai Bok

Answers:


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

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


对。也支持较新的TLS版本的好主意:面向未来。
Jordan Rieger 2014年

1
为了他人的利益,您提到的注册表编辑也可以通过以下步骤完成:serverfault.com/a/637263/98656。在Windows Server 2003至2012 R2中,协议受HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ Schannel \ Protocols中的标志控制。要禁用SSLv3,请在上述位置创建一个名为“ SSL 3.0”的子项,然后在该位置下创建一个名为“服务器”的子项,并在该位置下将一个名为“ Enabled”的DWORD值设置为0。您还应禁用SSL 2.0以同样的方式。
Jordan Rieger 2014年

4
@ScotterMonkey如果要从.NET代码启动出站连接,例如,从服务器上运行的自定义代码连接到Web服务或API,则只需设置System.Net.ServicePointManager.SecurityProtocol 。如果您仅运行一个简单的网站,并且仅接受来自浏览器的传入连接,则注册表修复程序就足够了。
Jordan Rieger 2014年

7
注意:出现,SecurityProtocolType.Tls11并且SecurityProtocolType.Tls12枚举值仅在ASP.net 4.5及更高版本中可用。不知道如果TLS 1.0被淘汰,我们将对在2.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。由于这是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)的服务器的代码。使用or'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月发布了此文章。他们对如何在各种版本的.net框架中完成此操作提出了很好的建议。


3
有趣。似乎文档页面已更新,同时MSDN移至“ .NET Framework (当前版本) ”,现在说明“故意未为此属性列出默认值”。也许更可靠的未来版本是首先查询属性以检索允许的协议列表,然后删除应用程序认为不安全的协议(即小于TLS 1.2的协议),而不是仅显式地添加您认为安全的产品。这不会在将来排除新版本。
约旦·里格

能够让程序从系统生成的列表中删除协议会很好,但是在当前的API中,我看不到这样做的方法。唯一的选择似乎是强制使用特定的协议,我不明白为什么有人愿意这么做。不幸的是,没有ALPN支持,这似乎是使TLS1.2连接正常工作的唯一方法。
冯·莱蒙加格尔教授

1
应该可以遍历所有SecurityProtocolType枚举,查看ServicePointManager.SecurityProtocol标志枚举中存在哪些枚举(它是所有设置标记的逻辑或,因此您可以使用AND测试每个标记),然后构建一个新的列出您不想删除的内容。然后将它们合并为一个枚举,并使用该枚举设置属性。
约旦·里格

我只是在重新阅读您的枚举/循环代码,但我认为这是不正确的。| =逻辑运算符将导致该属性包括最初在属性中设置的任何默认值,而不是仅包含Tls12及更高版本。要解决此问题,必须初始化一个值为0的SecurityProtocolType枚举变量,对该变量执行| =循环,然后将其分配给ServicePointManager.SecurityProtocol属性。
约旦·里格

7
没有其他人会发现.NET不能自动协商其能够达到的最高协议版本吗?
拉曼

5

@沃森

在Windows窗体上,该类位于顶部

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

因为Windows是单线程的,所以它所需要的就是它,如果它是一项服务,则需要将其放在该服务的调用上方(因为没有告诉您将使用哪个线程)。

using System.Security.Principal 

也需要。


5

如果您想知道.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攻击,并且没有可用的最佳密码套件。TLS 1.0客户端以及许多更现代的密码套件均无法使用诸如AES-GCM和SHA256之类的替代品来替代MD5-SHA-1。

如Eddie上面所述,您可以手动启用更好的协议:

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。因此,您可以在.NET 4.0应用程序中添加此代码(或添加按位“或”以添加对TLS 1.2协商的支持)并进行构建,但是您需要在.NET 4.5或更高版本上部署代码。blogs.perficient.com/microsoft/2016/04/tsl-1-2-and-net-support
rboy

还可以看到,.NET 4.0代码在更高版本的.NET(包括.NET 4.5和.NET 4.6)上都可以正常工作stackoverflow.com/questions/33378902/…–
rboy

整数强制转换可用于发送TLS 1.2。Tls12枚举值只是在.NET 4.0中不存在
CZahrobsky

两个不同点。看到我的评论。您可以输入该值,但是如果您的运行时Net版本为4.0,它将失败。您可以使用此标志进行编译,但是您的运行时.NET版本必须为4.5或更高版本,因为.NET 4.0上的基本组件不支持TLS 1.2所需的密码(请参阅链接)
rboy

2
对于较早的.NET运行时版本,有几个修补程序可以添加TLS 1.2支持。例如,support.microsoft.com /en-us/help/3154518/…,CZahrobsky可能还已经在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/zh-cn/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/zh-cn/windows-server/security/tls/tls-registry-settings#tls-10

https://docs.microsoft.com/zh-cn/windows-server/security/tls/tls-registry-settings#tls-11


注册表设置可以替代代码,但是这些设置是否实际上禁用了TLS 1.0和1.1,而仅允许使用TLS 1.2及更高版本的客户端连接?根据链接,它似乎仅禁用TLS中的RC4。我认为贵宾犬的攻击范围更广。
约旦·里格

@JordanRieger这些注册表项允许.NET客户端连接到已禁用旧协议以减轻POODLE的服务器。没有这些,客户端将抛出错误,因为.NET客户端愚蠢地坚持使用较旧的协议,即使服务器要求使用较新的协议也是如此。如果您的服务器仍允许使用较旧的协议进行连接,则所有选择均无效。从理论上讲,较早的协议应该被禁用。我想知道允许在服务器上禁用这些注册表项的注册表项(例如nartac.com/Products/IISCrypto)是否也适用于客户端?
拉曼

在nartac操纵的注册表项中,(充当)客户端和(充当)服务器有单独的设置。我不记得他们的界面是否与众不同。您知道什么版本的.net支持此注册表黑客吗?
冯·莱蒙加格尔教授

但是,@ Raman的问题是要减轻客户端连接到不受控制的服务器时的POODLE漏洞。该漏洞将使MITM攻击者将协议降级为可被黑客入侵的旧TLS或SSL版本。仅禁用RC4是不够的。这些注册表设置在某些情况下可能很有用,但在我的问题中没有用。
约旦·里格

1
@JordanRieger同意。我用其他一些观察和想法更新了本文。
拉曼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.