与最多支持 TLS 1.2
的服务器通信的默认安全协议是什么?默认情况下会 .NET
,选择服务器端支持的最高安全协议,还是我必须明确添加这行代码:
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.0
和 1.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
设置为特定值意味着您的应用程序将无法利用未来可能成为 .NET 更新中默认值的 TLS 版本。不要指定固定的协议列表,而是执行以下操作:
对于 .NET 4.7 或更高版本,不要设置 System.Net.ServicePointManager.SecurityProtocol
。默认值 (SecurityProtocolType.SystemDefault
) 将允许操作系统使用它知道并已配置的任何版本,包括在创建应用程序时可能不存在的任何新版本。
对于早期版本的 .NET Framework,您可以改为打开或关闭您知道和关心的协议,而让其他任何协议保持原样。
在不影响其他协议的情况下开启 TLS 1.1 和 1.2:
System.Net.ServicePointManager.SecurityProtocol |=
SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
注意使用 |=
打开这些标志而不关闭其他标志。
在不影响其他协议的情况下关闭 SSL3:
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
项目中手动设置枚举值来验证这一点:
ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 |
(SecurityProtocolType)768 | (SecurityProtocolType)3072;
参考:
namespace System.Net
{
[System.Flags]
public enum SecurityProtocolType
{
Ssl3 = 48,
Tls = 192,
Tls11 = 768,
Tls12 = 3072,
}
}
如果您在仅安装了 .NET 4.0
的环境中尝试破解,您将遇到异常:
未处理的异常:System.NotSupportedException:不支持请求的安全协议。在 System.Net.ServicePointManager.set_SecurityProtocol(SecurityProtocolType 值)
但是,我不推荐这种“hack”,因为未来的补丁等可能会破坏它。*
因此,我决定删除对 SSLv3
的支持的最佳途径是:
将所有应用程序升级到 .NET 4.5 将以下内容添加到引导代码以覆盖默认值和未来证明:System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |安全协议类型.Tls11 |安全协议类型.Tls12;
*如果这个黑客是错误的,有人纠正我,但我看到它的初始测试有效
ServicePointManager.cs
的源代码,请参阅 referencesource.microsoft.com/#System/net/System/Net/…
.NET 4.5
默认为 Tls12 - 但正如您在这里所说的那样,它没有。它使您可以选择将其用于 SecurityProtocol
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12
您可以覆盖以下注册表中的默认行为:
Key : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319
Value: SchUseStrongCrypto
Type: REG_DWORD
Data : 1
和
Key : HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319
Value: SchUseStrongCrypto
Type: REG_DWORD
Data : 1
有关详细信息,请参阅implementation of ServicePointManager
。
reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:64
(和/或 /reg:32
)
创建一个带有 .reg
扩展名和以下内容的文本文件:
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
或从以下来源下载:
双击安装...
我发现当我只指定 TLS 1.2 时,它仍然会向下协商到 1.1。 System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
我已经在我的 .net 4.5 Web 应用程序的 Global.asax 启动方法中指定了这一点。
以下代码将:
打印启用协议
打印可用的协议
启用 TLS1.2 如果平台支持它并且如果它没有启用开始
如果启用 SSL3,则禁用它
打印最终结果
常数:
48 是 SSL3
192 是 TLS1
768 是 TLS1.1
3072 是 TLS1.2
其他协议不会受到影响。这使得它与未来的协议(Tls1.3 等)兼容。
代码
// 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);
输出
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
当我的客户将 TLS 从 1.0 升级到 1.2 时,我遇到了问题。我的应用程序使用 .net framework 3.5 并在服务器上运行。所以我通过这种方式修复了它:
修复程序
在调用 HttpWebRequest.GetResponse() 之前添加以下命令:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolTypeExtensions.Tls11 | SecurityProtocolTypeExtensions.Tls12;
通过添加 2 个新类扩展 2 个 DLL:System.Net 和 System.Security.Authentication
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;
}
}
更新微软批处理
批量下载:
对于 Windows 2008 R2:windows6.1-kb3154518-x64.msu
对于 Windows 2012 R2:windows8.1-kb3154520-x64.msu
有关下载批次和更多详细信息,您可以在此处查看:
经过一番斗争,注册表更改机制对我有用。实际上我的应用程序运行为 32 位。所以我不得不改变路径下的值。
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft.NETFramework\v4.0.30319
https://i.stack.imgur.com/NGeTH.png
我在 .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+ 并将选择适当协议的更多责任移交给操作系统时,这也将继续做出正确的决定,我采用了以下代码:
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 时升级到新的安全协议不可避免地被破坏,或者您更有可能不得不在您的服务器上打开现有的不安全协议多年,从而使您的组织成为攻击的目标。
SecurityProtocolType.SystemDefault
标志的计算结果为 0
,因此使用 TLS 1.2 的按位包含或标志检查 if (securityProtocols == 0)
将始终包括 TLS 1.2,即使它是“休息”,对吧?这里没有锐利的拍摄。我真的在努力寻找最好的前进道路。
if (!Enum.IsDefined(typeof(SecurityProtocolType), 0) && securityProtocols == 0) { securityProtocols |= SecurityProtocolType.Tls12; }
。
securityProtocols |= SecurityProtocolType.Tls12;
(没有 if 块)不维护 SystemDefault,securityProtocols 之后只有 TLS2。那么您的意思是当值为 SystemDefault 时,不应更新任何值?关于前向兼容,您是否假设操作系统会负责启用像 TLS 1.3 这样的新协议?
securityProtocols |= SecurityProtocolType.Tls12;' will add TLS 1.2, but because the
SecurityProtocolType` 行枚举有一个 [Flags]
属性,并且 SystemDefault 枚举值为 0
,SystemDefault 值将被剥离,即使它之前已设置。最终结果是您可以将 SevicePointManager.SecurityProtocol
设置为 0,或者设置为其他枚举值的任意组合。如果您将其设置为 SystemDefault,则您基本上选择不自己指定协议并让操作系统决定。
微软最近发布了关于此的最佳实践。 https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls
概括
以 .Net Framework 4.7 为目标,删除任何设置 SecurityProtocol 的代码,因此操作系统将确保您使用最安全的解决方案。
注意:您还需要确保您的操作系统支持并启用最新版本的 TLS。
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\TLS 1.2\Server
Property: Enabled
Type: REG_DWORD
Value: 1
Property: DisabledByDefault
Type: REG_DWORD
Value: 0
Path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client
Property: Enabled
Type: REG_DWORD
Value: 1
Property: DisabledByDefault
Type: REG_DWORD
Value: 0
有关更多信息和旧框架,请参阅 MS 链接。
if (System.Environment.OSVersion.Version < new Version(6, 2) /* Windows 8 */) ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; else ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault;
为了完整起见,这是一个设置上述注册表项的 Powershell 脚本:
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 framework 4.5 或更低版本上运行,并且您可以轻松地将新代码部署到生产环境中,那么您可以使用以下解决方案。您可以在进行 api 调用之前添加以下代码行,ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // .NET 4.5 如果您无法部署新代码并且想要使用生产中存在的相同代码进行解析,那么您有两种选择。
选项1 :
[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
然后创建一个扩展名为 .reg 的文件并安装。
注意:此设置将在注册表级别应用,并适用于该计算机上存在的所有应用程序,如果您想限制为仅单个应用程序,则可以使用 Option 2
选项 2:这可以通过更改配置文件中的一些配置设置来完成。您可以在配置文件中添加其中任何一个。
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
</runtime>
或者
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=false"
</runtime>
硬编码 ServicePointManager.SecurityProtocol
或上面提到的显式 SchUseStrongCrypto 键的替代方法:
您可以告诉 .NET 使用带有 SystemDefaultTlsVersions 键的默认 SCHANNEL 设置,
例如:
[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
此问题的最佳解决方案似乎是至少升级到 .NET 4.6 或更高版本,它将自动选择强协议和强密码。
如果无法升级到 .NET 4.6,建议设置
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 |安全协议类型.Tls12;
并使用注册表设置:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319 – SchUseStrongCrypto = DWORD of 1 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft.NETFramework\v4.0.30319 – SchUseStrongCrypto = DWORD of 1
导致使用 TLS 1.0 和强密码以外的东西。
在我的测试中,只有 Wow6432Node 中的设置有任何不同,即使我的测试应用程序是为任何 CPU 构建的。
根据 Transport Layer Security (TLS) best practices with the .NET Framework:为确保 .NET Framework 应用程序保持安全,TLS 版本不应被硬编码。 而是设置注册表项:SystemDefaultTlsVersions
和 SchUseStrongCrypto
:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v2.0.50727]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v2.0.50727]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
如果您可以使用 .NET 4.7.1 或更高版本,它将使用 TLS 1.2 作为基于操作系统功能的最低协议。根据微软的建议:
To ensure .NET Framework applications remain secure, the TLS version should not be hardcoded. .NET Framework applications should use the TLS version the operating system (OS) supports.
对于密钥:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319 值:SchUseStrongCrypto
您必须将值设置为 1。
[Net.ServicePointManager]::SecurityProtocol = ([Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12)
Invoke-RestMethod 依赖于相同的底层 .NET 框架库。Net.ServicePointManager.SecurityProtocol = Net.ServicePointManager.SecurityProtocol OR Net.SecurityProtocolType.Tls12 OR Net.SecurityProtocolType.Tls12