关于安全性:.NET 4.5中的默认安全协议

Default SecurityProtocol in .NET 4.5

与最多支持TLS 1.2的服务器通信的默认安全协议是什么?默认情况下,.NET会选择服务器端支持的最高安全协议,还是必须显式添加这行代码:

1
2
System.Net.ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

除了代码更改之外,还有什么方法可以更改这个默认值吗?

最后,.NET 4.0是否只支持到TLS 1.0?也就是说,我必须将客户项目升级到4.5以支持TLS 1.2

我的动机是在客户端删除对SSLv3的支持,即使服务器支持(我已经有一个PowerShell脚本在计算机注册表中禁用它),并支持服务器支持的最高TLS协议。

更新:看.NET 4.0中的ServicePointManager类,我看不到TLS 1.01.1的枚举值。在两个.NET 4.0/4.5中,默认值都是SecurityProtocolType.Tls|SecurityProtocolType.Ssl3。希望通过在注册表中禁用SSLv3,这个默认不会被打破。

不过,我决定将所有应用程序升级到.NET 4.5,并将SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;明确添加到所有应用程序的所有引导代码中。

这将向各种API和服务发出出站请求,使其不降级到SSLv3,并应选择TLS的最高级别。

这种方法听起来合理还是过度杀伤力?我有许多应用程序需要更新,我希望将来能证明它们,因为我听说甚至TLS 1.0在不久的将来可能会被一些提供商否决。

作为向API发出出站请求的客户端,在注册表中禁用ssl3是否在.NET框架中也有影响?我看到在默认情况下,没有启用TLS 1.1和1.2,我们必须通过注册表启用它吗?请访问http://support.microsoft.com/kb/245030。

经过一点调查,我相信注册表设置不会有影响,因为它们适用于IIS(服务器子项)和浏览器(客户端子项)。

很抱歉,这篇文章变成了多个问题,接下来是"可能"的答案。


一些留下评论的人指出,将System.Net.ServicePointManager.SecurityProtocol设置为特定值意味着您的应用程序将无法利用将来的tls版本,这些版本可能会成为.net未来更新中的默认值。代替指定一个固定的协议列表,您可以打开或关闭您知道和关心的协议,让其他协议保持原样。

要在不影响其他协议的情况下打开TLS 1.1和1.2:

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

注意使用|=打开这些标志而不关闭其他标志。

要在不影响其他协议的情况下关闭SSL3:

1
System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3;


两个.NET 4.0/4.5中的默认System.Net.ServicePointManager.SecurityProtocol都是SecurityProtocolType.Tls|SecurityProtocolType.Ssl3

.NET 4.0支持多达TLS 1.0.NET 4.5支持多达TLS 1.2

但是,如果在同一环境中安装了.NET 4.5,那么面向.NET 4.0的应用程序仍然可以支持多达TLS 1.2.NET 4.5安装在.NET 4.0的顶部,取代System.dll

我通过观察与fiddler4通信中设置的正确安全协议以及在.NET 4.0项目中手动设置枚举值来验证这一点:

1
2
ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 |
(SecurityProtocolType)768 | (SecurityProtocolType)3072;

参考文献:

1
2
3
4
5
6
7
8
9
10
11
namespace System.Net
{
    [System.Flags]
    public enum SecurityProtocolType
    {
       Ssl3 = 48,
       Tls = 192,
       Tls11 = 768,
       Tls12 = 3072,
    }
}

如果您试图在仅安装了.NET 4.0的环境上进行黑客攻击,则会得到以下异常:

Unhandled Exception: System.NotSupportedException: The requested security protocol is not supported.
at System.Net.ServicePointManager.set_SecurityProtocol(SecurityProtocolType v
alue)

但是,我不推荐这种"黑客",因为将来的补丁等可能会破坏它。*

因此,我决定取消对SSLv3的支持的最佳途径是:

  • 将所有应用程序升级到.NET 4.5
  • 将以下内容添加到bootstrapping代码中,以覆盖默认和将来的证明:

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

  • *如果这个黑客是错误的,有人会纠正我,但初步测试我看是有效的。


    您可以覆盖以下注册表中的默认行为:

    1
    2
    3
    4
    Key  : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319
    Value: SchUseStrongCrypto
    Type: REG_DWORD
    Data : 1

    1
    2
    3
    4
    Key  : HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319
    Value: SchUseStrongCrypto
    Type: REG_DWORD
    Data : 1

    具体见ServicePointManager的实施。


    创建扩展名为.reg的文本文件,内容如下:

    1
    2
    3
    4
    5
    6
    7
    Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
    "SchUseStrongCrypto"=dword:00000001

    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319]
    "SchUseStrongCrypto"=dword:00000001

    或从以下来源下载:

    https://tls1test.salesforce.com/s/net40-enable-tls-1_2.reg

    双击以安装…


    我发现,当我只指定TLS 1.2时,它仍将协商到1.1。System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

    我已经在.NET 4.5 Web应用程序的global.asax启动方法中指定了这一点。


    经过一番斗争,注册表更改机制对我有效。实际上,我的应用程序以32位运行。所以我必须改变路径下的值。

    1
    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft.NETFramework\v4.0.30319

    值类型必须是双字且值大于0。最好使用1.Registry settings to get .Net 4.0 app use TLS 1.2 provided .Net 4.5 is installed in the machine.


    我的客户将tls从1.0升级到1.2时遇到问题。我的应用程序正在使用.NET Framework 3.5并在服务器上运行。所以我就这样解决了:

  • 修复程序
  • 在调用httpwebrequest.getresponse()之前,请添加以下命令:

    1
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolTypeExtensions.Tls11 | SecurityProtocolTypeExtensions.Tls12;

    通过添加2个新类来扩展2个DLL:System.net和System.Security.Authentication

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
        namespace System.Net
        {
            using System.Security.Authentication;
            public static class SecurityProtocolTypeExtensions
            {
                public const SecurityProtocolType Tls12 = (SecurityProtocolType)SslProtocolsExtensions.Tls12;
                public const SecurityProtocolType Tls11 = (SecurityProtocolType)SslProtocolsExtensions.Tls11;
                public const SecurityProtocolType SystemDefault = (SecurityProtocolType)0;
            }
        }

        namespace System.Security.Authentication
        {
            public static class SslProtocolsExtensions
            {
                public const SslProtocols Tls12 = (SslProtocols)0x00000C00;
                public const SslProtocols Tls11 = (SslProtocols)0x00000300;
            }
        }
  • 更新Microsoft批处理
  • 下载批处理:

    • 对于Windows 2008 R2:windows6.1-kb3154518-x64.msu
    • 对于Windows 2012r2:windows8.1-kb3154520-x64.msu

    有关下载批次和更多详细信息,请参见以下内容:

    https://support.microsoft.com/en-us/help/3154518/support for tls system default versions included in the-.net-framework-3.5.1-on-windows-7-sp1-and-server-2008-r2-sp1


    以下代码将:

    • 支持打印的协议
    • 打印可用协议
    • 如果平台支持TLS1.2,且未启用,则启用该TLS1.2。
    • 如果启用了SSL3,则禁用它
    • 打印最终结果

    常数:

    • 48是SSL3
    • 192是TLS1
    • 768是TLS1.1
    • 3072是TLS1.2

    其他协议不会受到影响。这使得它与未来的协议(TLS1.3等)兼容。

    代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // print initial status
        Console.WriteLine("Runtime:" + System.Diagnostics.FileVersionInfo.GetVersionInfo(typeof(int).Assembly.Location).ProductVersion);
        Console.WriteLine("Enabled protocols:  " + ServicePointManager.SecurityProtocol);
        Console.WriteLine("Available protocols:");
        Boolean platformSupportsTls12 = false;
        foreach (SecurityProtocolType protocol in Enum.GetValues(typeof(SecurityProtocolType))) {                
            Console.WriteLine(protocol.GetHashCode());
            if (protocol.GetHashCode() == 3072){
                platformSupportsTls12 = true;
            }
        }
        Console.WriteLine("Is Tls12 enabled:" + ServicePointManager.SecurityProtocol.HasFlag((SecurityProtocolType)3072));    


    // enable Tls12, if possible
        if (!ServicePointManager.SecurityProtocol.HasFlag((SecurityProtocolType)3072)){
            if (platformSupportsTls12){
                Console.WriteLine("Platform supports Tls12, but it is not enabled. Enabling it now.");
                ServicePointManager.SecurityProtocol |= (SecurityProtocolType)3072;
            } else {
                Console.WriteLine("Platform does not supports Tls12.");
            }
        }

    // disable ssl3
       if (ServicePointManager.SecurityProtocol.HasFlag(SecurityProtocolType.Ssl3)) {
          Console.WriteLine("Ssl3SSL3 is enabled. Disabling it now.");
          // disable SSL3. Has no negative impact if SSL3 is already disabled. The enclosing"if" if just for illustration.
          System.Net.ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3;                      
       }
        Console.WriteLine("Enabled protocols:  " + ServicePointManager.SecurityProtocol);

    产量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Runtime: 4.7.2114.0
    Enabled protocols:   Ssl3, Tls
    Available protocols:
    0
    48
    192
    768
    3072
    Is Tls12 enabled: False
    Platform supports Tls12, but it is not enabled. Enabling it now.
    Ssl3 is enabled. Disabling it now.
    Enabled protocols:   Tls, Tls12

    我在.NET 4.5.2下运行,我对这些答案都不满意。当我正在与一个支持TLS 1.2的系统交谈时,看到SSL3、TLS 1.0和TLS 1.1都已损坏,无法安全使用,我不想启用这些协议。在.NET 4.5.2下,ssl3和tls 1.0协议都默认启用,我可以通过检查ServicePointManager.SecurityProtocol在代码中看到。在.NET 4.7下,有新的SystemDefault协议模式,它明确地将协议的选择移交给操作系统,我相信依赖注册表或其他系统配置设置是合适的。然而,在.NET 4.5.2下似乎不支持这种方法。为了编写向前兼容的代码,即使将来不可避免地会破坏TLS 1.2,或者当我升级到.NET 4.7+并将更多的责任移交给操作系统以选择合适的协议时,我仍然会做出正确的决定,我采用了以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SecurityProtocolType securityProtocols = ServicePointManager.SecurityProtocol;
    if (securityProtocols.HasFlag(SecurityProtocolType.Ssl3) || securityProtocols.HasFlag(SecurityProtocolType.Tls) || securityProtocols.HasFlag(SecurityProtocolType.Tls11))
    {
        securityProtocols &= ~(SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11);
        if (securityProtocols == 0)
        {
            securityProtocols |= SecurityProtocolType.Tls12;
        }
        ServicePointManager.SecurityProtocol = securityProtocols;
    }

    此代码将检测何时启用了已知的不安全协议,在这种情况下,我们将删除这些不安全协议。如果没有其他显式协议,那么我们将强制启用tls 1.2,这是.NET目前唯一支持的安全协议。这段代码是向前兼容的,因为它将考虑将来不知道要添加的新协议类型,而且它还可以很好地处理.NET 4.7中的新SystemDefault状态,这意味着将来我不必重新访问这段代码。我强烈建议采用这样的方法,而不是无条件地硬编码任何特定的安全协议状态,否则当TLS 1.2不可避免地被破坏时,您必须重新编译并用新版本替换您的客户机,以便升级到新的安全协议,或者更可能您必须离开现有的inse。在您的服务器上启用多年的修复协议,使您的组织成为攻击的目标。


    微软最近发布了有关这方面的最佳实践。https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls

    总结

    目标.NET Framework 4.7,删除设置SecurityProtocol的任何代码,这样操作系统将确保您使用最安全的解决方案。

    注意:您还需要确保在操作系统上支持和启用最新版本的TLS。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    OS                          TLS 1.2 support

    Windows 10                  \_ Supported, and enabled by default.
    Windows Server 2016         /  
    Windows 8.1                 \_ Supported, and enabled by default.
    Windows Server 2012 R2      /
    Windows 8.0                 \_ Supported, and enabled by default.
    Windows Server 2012         /
    Windows 7 SP1               \_ Supported, but not enabled by default*.
    Windows Server 2008 R2 SP1  /
    Windows Server 2008         -  Support for TLS 1.2 and TLS 1.1 requires an update. See Update to add support for TLS 1.1 and TLS 1.2 in Windows Server 2008 SP2.
    Windows Vista               -  Not supported.

    * To enable TLS1.2 via the registry see https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-12

        Path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS1.2\Server

            Property: Enabled
            Type: REG_DWORD
            Value: 1

            Property: DisabledByDefault
            Type: REG_DWORD
            Value: 0

        Path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS1.2\Client

            Property: Enabled
            Type: REG_DWORD
            Value: 1

            Property: DisabledByDefault
            Type: REG_DWORD
            Value: 0

    有关更多信息和旧框架,请参阅MS链接。


    为完整起见,下面是一个设置上述注册表项的PowerShell脚本:

    1
    2
    new-itemproperty -path"HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -name"SchUseStrongCrypto" -Value 1 -PropertyType"DWord";
    new-itemproperty -path"HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" -name"SchUseStrongCrypto" -Value 1 -PropertyType"DWord"


    这个问题的最佳解决方案似乎是升级到至少.NET 4.6或更高版本,它将自动选择强协议和强密码。

    如果无法升级到.NET 4.6,则建议

    system.net.servicePointManager.securityProtocol=securityProtocolType.tls11 securityProtocolType.tls12;

    并使用注册表设置:

    hkey_local_machinesoftwaremicrosoft.netframeworkv4.0.30319–schosestrongcrypto=1的双字hkey_local_machinesoftwarewow6432nodemicrosoft.netframeworkv4.0.30319–schosestrongcrypto=1的双字

    结果使用的不是tls 1.0和强密码。

    在我的测试中,尽管我的测试应用程序是为任何CPU构建的,但是只有wow6432节点中的设置有任何不同。


    上述硬编码ServicePointManager.SecurityProtocol或显式Schusestrongcrypto键的替代方案:您可以告诉.NET使用带有SystemDefaultTlsVersions键的默认schannel设置,例如。:

    1
    2
    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]"SystemDefaultTlsVersions"=dword:00000001
    [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319]"SystemDefaultTlsVersions"=dword:00000001

    对于密钥:hkey_local_machinesoftwaremicrosoft.netframeworkv4.0.30319值:schosestrongcrypto

    必须将值设置为1。