.NET Framework 中的传输层安全性 (TLS) 最佳做法
注意
本页包含 .NET Framework TLS 信息。 如果你要查找 .NET TLS 信息,请参阅:TLS /SSL 最佳做法
.NET Framework 支持使用传输层安全性 (TLS) 协议来保护网络通信。
什么是传输层安全性 (TLS)?
警告
RFC8996 已弃用 TLS 1.0 和 1.1。 本文档仅涵盖 TLS 1.2 和 TLS 1.3。
传输层安全性 (TLS) 协议是最新版本的行业标准,旨在帮助保护通过 Internet 传输的信息的私密性。 TLS 1.3 标准与以前版本相比在安全性方面有了很多提升。 文本介绍了如何保护使用 TLS 协议的 .NET Framework 应用程序安全的建议。
谁可以从本文档中受益?
- 直接使用 System.Net API(例如,System.Net.Http.HttpClient 和 System.Net.Security.SslStream)。
- 直接使用 WCF 客户端和使用 System.ServiceModel 命名空间的服务。
.NET Framework 中的 TLS 支持
由于 .NET Framework 依赖于 Windows 上的 Schannel
,因此可以协商哪些版本以及要使用哪个版本将取决于操作系统。
下面是更新的示例表,其中显示了操作系统版本和 .NET Framework 目标版本的不同组合所支持的最高 TLS 版本:
.NET Framework 目标版本 | Windows 10 | Windows 11 |
---|---|---|
3.5 | TLS 1.2 | TLS 1.2 |
4.6.2 | TLS 1.2 | TLS 1.3 |
4.7 | TLS 1.2 | TLS 1.3 |
4.7.1 | TLS 1.2 | TLS 1.3 |
4.7.2 | TLS 1.2 | TLS 1.3 |
4.8 | TLS 1.2 | TLS 1.3 |
4.8.1 | TLS 1.2 | TLS 1.3 |
有关详细信息,请参阅 Schannel 中的 TLS 协议版本支持。
建议
- 对于 TLS 1.3,面向 .NET Framework 4.8 或更高版本。 查看审核代码部分,了解如何验证你的
target framework
。 - 不要显式指定 TLS 版本,即不要使用获取显式
SslProtocols
参数的SslStream
的方法重载。- 这样,你的代码将让操作系统决定 TLS 版本。
- 如果必须设置 ServicePointManager.SecurityProtocol,则将其设置为 SecurityProtocolType.SystemDefault。 这也将使用操作系统默认值。
- 如果必须使用获取显式
SslProtocols
参数的SslStream
的方法重载,则以参数的形式传递SslProtocols.SystemDefault
。 这也将使用操作系统默认值。
- 执行全面的代码审核,以验证你是否未显式指定 TLS 或 SSL 版本。
警告
请勿使用 SslProtocols.Default
,因为它将 TLS 版本设置为已过时的 SSL3 和 TLS 1.0。
当你的应用让操作系统来选择 TLS 版本时:
- 它将会自动利用将来添加的新 TLS 协议。
- 操作系统将阻止已发现的不安全协议(如 SSL3 和 TLS 1.0)。
本文说明了如何启用可用于应用所面向并在其上运行的 .NET Framework 版本的最强安全性。 当应用显式设置安全协议和版本时,它将选择退出任何其他替代项,并选择退出 .NET Framework 和操作系统默认行为。 如果你希望应用能够协商 TLS 1.3 连接,请显式设置为较低的 TLS 版本,以阻止 TLS 1.3 连接。
如果你不得不显式指定协议版本,我们强烈建议指定 TLS 1.2 或 TLS 1.3(这些是 currently considered secure
)。 有关标识和删除 TLS 1.0 依赖项的指南,请下载解决 TLS 1.0 问题白皮书。
WCF 支持使用 TLS 1.2 作为 .NET Framework 4.7 中的默认设置。 从 .NET Framework 4.7.1 开始,WCF 默认为操作系统配置的版本。 如果某个应用程序使用 SslProtocols.None
显式配置,则在使用 NetTcp 传输时,WCF 将使用操作系统默认设置。
你可以在 GitHub 问题 .NET Framework 中的传输层安全性 (TLS) 最佳做法中提问有关此文档的问题。
审核代码并对代码进行更改
对于 ASP.NET 应用程序,请检查 web.config 的 <system.web><httpRuntime targetFramework>
元素,以验证你使用的是否为 .NET Framework 的目标版本。
有关 Windows 窗体和其他应用程序,请参阅如何:面向 .NET Framework 的某个版本。
使用以下部分验证你未使用特定 TLS 或 SSL 版本。
如果必须显式设置安全协议
如果必须显式设置安全协议而不是让 .NET 或操作系统选择安全协议,请选择以下协议:
- 对于 .NET Framework 3.5:TLS 1.2
- 对于 .NET Framework 4.6.2 或更高版本:TLS 1.3
如果在 enum 中找不到指定的协议,可以将其添加为扩展文件。 请参见下图:
SslProtocolExtensions.cs
namespace System.Security.Authentication
{
public static class SslProtocolsExtensions
{
// For .NET Framework 3.5
public const SslProtocols Tls12 = (SslProtocols)3072;
// For .NET Framework 4.6.2 and later
public const SslProtocols Tls13 = (SslProtocols)12288;
}
}
SecurityProtocolExtensions.cs
using System.Security.Authentication;
namespace System.Net
{
public static class SecurityProtocolTypeExtensions
{
// For .NET Framework 3.5
public const SecurityProtocolType Tls12 = (SecurityProtocolType)SslProtocolsExtensions.Tls12;
// For .NET Framework 4.6.2 and later
public const SecurityProtocolType Tls13 = (SecurityProtocolType)SslProtocolsExtensions.Tls13;
}
}
有关详细信息,请参阅在 Windows 8.1 和 Windows Server 2012 R2 上的 .NET Framework 3.5 中包含对 TLS 系统默认版本的支持。
对于 System.Net API(HttpClient、SslStream)
如果你的应用面向 .NET Framework 4.7 或更高版本
以下部分介绍如何将应用程序配置为使用 TLS 的 currently considered secure versions
。 (TLS 1.2、TLS 1.3)
对于 HttpClient 和 HttpWebRequest
使用 .NET Framework 4.7 及更高版本的 ServicePointManager 将使用操作系统中配置的默认安全协议。 若要获取默认操作系统选择,如有可能,请不要设置 ServicePointManager.SecurityProtocol 属性的值,该值默认为 SecurityProtocolType.SystemDefault。
由于 SecurityProtocolType.SystemDefault 设置会导致 ServicePointManager 使用由操作系统配置的默认安全协议,因此应用程序可能会根据运行的操作系统以不同的方式运行。 例如,Windows 10 使用 TLS 1.2,而 Windows 11 则使用 TLS 1.3。
对于 SslStream
SslStream,使用 .NET Framework 4.7 和更高版本,默认为由操作系统选择最佳安全协议和版本。 若要获取默认操作系统最佳选择,如有可能,请不要使用采取显式 SslProtocols 参数的 SslStream 的方法重载。 否则,将传递 SslProtocols.None。 建议不要使用 Default;设置 SslProtocols.Default
会强制使用 SSL 3.0 /TLS 1.0,而不使用 TLS 1.2。
不要设置 SecurityProtocol 属性的值(针对 HTTP 网络)。
不要使用采取显式 SslProtocols 参数的 SslStream 的方法重载(针对 TCP 套接字网络)。 当你将应用重定向到 .NET Framework 4.7 或更高版本时,将遵循最佳做法建议。
对于 WCF 应用程序
如果你的应用面向 .NET Framework 4.7 或更高版本
以下部分介绍如何将应用程序配置为使用 TLS 的 currently considered secure versions
。 (TLS 1.2、TLS 1.3)
通过具有证书凭据的传输安全性使用 TCP 传输
WCF 使用与 .NET Framework 的其余部分相同的网络堆栈。
如果你面向的是 4.7.1,则 WCF 将配置为默认允许操作系统选择最佳安全协议(除非显式对其配置):
- 在你的应用程序配置文件中。
- 或者,在你的源代码中的应用程序中。
默认情况下,.NET Framework 4.7 和更高版本将配置为使用 TLS 1.2,并允许使用 TLS 1.1 或 TLS 1.0 进行连接。 通过将你的绑定配置为使用 SslProtocols.None 来配置 WCF,以允许操作系统选择最佳安全协议。 可在 SslProtocols 上进行此设置。 SslProtocols.None
可以从 Transport 中进行访问。 NetTcpSecurity.Transport
可以从 Security 中进行访问。
如果你使用自定义绑定:
- 通过将 SslProtocols 设置为使用 SslProtocols.None 来配置 WCF,以允许操作系统选择最佳安全协议。
- 或者,配置在配置路径
system.serviceModel/bindings/customBinding/binding/sslStreamSecurity:sslProtocols
中使用的协议。
如果你没有 使用自定义绑定, 且正使用配置来设置你的 WCF 绑定,则设置配置路径 system.serviceModel/bindings/netTcpBinding/binding/security/transport:sslProtocols
中使用的协议。
使用具有证书凭据的消息安全性
默认情况下,.NET Framework 4.7 和更高版本使用 SecurityProtocol 属性中指定的协议。 当 AppContextSwitchSwitch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols
设置为 true
时,WCF 将选择最佳协议(最高至 TLS 1.0)。
如果你的应用面向 .NET Framework 4.7 之前的版本
以下部分介绍如何将应用程序配置为使用 TLS 的 currently considered secure versions
。 (TLS 1.2、TLS 1.3)
通过具有证书凭据的 TCP 传输安全性使用 .NET Framework 4.6.2
除非显式配置协议版本,否则 WCF 框架将自动选择高至 TLS 1.2 的最高协议。 有关详细信息,请参阅上一部分对于使用具有证书凭据的传输安全性的 WCF TCP 传输。
通过具有证书凭据的 TCP 传输安全性使用 .NET Framework 3.5
这些版本的 WCF 框架显式指定为使用值 SSL 3.0 和 TLS 1.0。 这些值不能更改。 必须更新并重新面向 NET Framework 4.6.2 或更高版本,以使用 TLS 1.2。
通过 AppContext 开关配置安全性(适用于 .NET Framework 4.6.2 或更高版本)
如果你的应用面向 .NET Framework 4.6.2 或更高版本或在其上运行,请参阅本部分所述的 AppContext 开关。 无论它们是默认设置还是对其显式设置,开关均应为 false
(如有可能)。 如果希望通过一个或这两个开关配置安全性,则不要在你的代码中指定安全协议值,执行此操作将会替代此开关。
对于 System.Net API(HttpClient、SslStream)
无论你使用 HTTP 网络 (ServicePointManager) 还是使用 TCP 套接字网络 (SslStream),开关都具有相同的效果。
Switch.System.Net.DontEnableSchUseStrongCrypto
Switch.System.Net.DontEnableSchUseStrongCrypto
的值为 false
将导致你的应用使用强加密。 DontEnableSchUseStrongCrypto
的值 false
将使用更为安全的网络协议(TLS 1.2 和 TLS 1.1),并阻止不安全的协议。 有关详细信息,请参阅 SCH_USE_STRONG_CRYPTO 标志。 值为 true
将为你的应用禁用强加密。 此交换机仅影响应用程序中的客户端(传出)连接。
如果你的应用面向 .NET Framework 4.6.2 或更高版本,则此开关默认为 false
。 这是我们建议使用的安全默认值。 如果你的应用在 .NET Framework 4.6.2 上运行,但面向更低版本,则开关默认为 true
。 在这种情况下,应显式将其设置为 false
。
如果需要连接到不支持强加密且无法升级的旧服务,则 DontEnableSchUseStrongCrypto
的值只能为 true
。
Switch.System.Net.DontEnableSystemDefaultTlsVersions
Switch.System.Net.DontEnableSystemDefaultTlsVersions
的值为 false
将导致你的应用允许操作系统选择协议。 值为 true
将导致你的应用使用由 .NET Framework 选取的协议。
如果你的应用面向 .NET Framework 4.7 或更高版本,则此开关默认为 false
。 这是我们建议使用的安全默认值。 如果你的应用在 .NET Framework 4.7 或更高版本上运行,但面向早期版本,则开关默认为 true
。 在这种情况下,应显式将其设置为 false
。
对于 WCF 应用程序
Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols
Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols
的值为 false
将导致你的应用程序使用 ServicePointManager.SecurityProtocols
中定义的值,以确保使用证书凭据的消息的安全性。 值为 true
将使用可用的最高协议(高至 TLS1.0)
对于面向 .NET Framework 4.7 和更高版本的应用程序,此值默认为 false
。 对于面向 .NET Framework 4.6.2 和早期版本的应用程序,此值默认为 true
。
Switch.System.ServiceModel.DontEnableSystemDefaultTlsVersions
Switch.System.ServiceModel.DontEnableSystemDefaultTlsVersions
的值为 false
将设置默认配置,以允许操作系统选择协议。 值为 true
会将默认值设置为可用的最高协议(高至 TLS1.2)。
对于面向 .NET Framework 4.7.1 和更高版本的应用程序,此值默认为 false
。 对于面向 .NET Framework 4.7 和早期版本的应用程序,此值默认为 true
。
有关 TLS 协议的详细信息,请参阅缓解措施:TLS 协议。 有关 AppContext
开关的详细信息,请参阅 <AppContextSwitchOverrides> Element
。
通过 Windows 注册表配置安全性
警告
设置注册表项会影响系统上的所有应用程序。 仅当你完全控制计算机并可以控制对注册表的更改时才可使用此选项。
如果不能设置一个或两个 AppContext
开关,可以使用本节中所述的 Windows 注册表项来控制应用所使用的安全协议。 如果你的应用在 .NET Framework 3.5 上运行或你无法编辑配置文件,则可能无法使用一个或两个 AppContext
开关。 如果想要在注册表中配置安全性,则不要在你的代码中指定安全协议,这样做将会替代该注册表设置。
注册表项的名称类似于相应 AppContext
开关的名称,但其不带预置的 DontEnable
。 例如,AppContext
开关 DontEnableSchUseStrongCrypto
是名为 SchUseStrongCrypto 的注册表项。
这些密钥在所有 .NET Framework 版本中都可用。
无论你使用 HTTP 网络 (ServicePointManager) 还是使用 TCP 套接字网络 (SslStream),下面介绍的所有注册表项都具有相同的效果。
SchUseStrongCrypto
HKEY_LOCAL_MACHINE\SOFTWARE\[Wow6432Node\]Microsoft\.NETFramework\<VERSION>: SchUseStrongCrypto
注册表项的值类型为 DWORD。 值为 1 将导致你的应用使用强加密。 强加密会使用更为安全的网络协议(TLS 1.2 和 TLS 1.1),并阻止不安全的协议。 值为 0 将禁用强加密。 有关详细信息,请参阅 SCH_USE_STRONG_CRYPTO 标志。 此注册表设置仅影响应用程序中的客户端(传出)连接。
如果你的应用面向 .NET Framework 4.6 或更高版本,则此注册表项默认值为 1。 这是我们建议使用的安全默认值。 如果你的应用面向 .NET Framework 4.5.2 或更高版本,则此注册表项默认为 0。 在这种情况下,应显式将其值设置为 1。
如果需要连接到不支持强加密且无法升级的旧服务,则此注册表项的值只能为 0。
SystemDefaultTlsVersions
HKEY_LOCAL_MACHINE\SOFTWARE\[Wow6432Node\]Microsoft\.NETFramework\<VERSION>: SystemDefaultTlsVersions
注册表项的值类型为 DWORD。 值为 1 将导致你的应用允许操作系统选择协议。 值为 0 将导致你的应用使用由 .NET Framework 选取的协议。
<VERSION>
必须为 v4.0.30319(对于 .NET Framework 4 和更高版本)或 v2.0.50727(对于 .NET Framework 3.5)。
如果你的应用面向 .NET Framework 4.7 或更高版本,则此注册表项默认值为 1。 这是我们建议使用的安全默认值。 如果你的应用面向 .NET Framework 4.6.1 或更高版本,则此注册表项默认为 0。 在这种情况下,应显式将其值设置为 1。
有关详细信息,请参阅 Windows 10 版本 1511 和 Windows Server 2016 Technical Preview 4 的累积更新:2016 年 5 月 10 日。
有关 .NET Framework 3.5.1 中的详细信息,请参阅在 Windows 7 SP1 和 Server 2008 R2 SP1 上的 .NET Framework 3.5.1 中包含对 TLS 系统默认版本的支持。
以下 .REG 文件将注册表项及其变量设置为其最安全的值:
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
在 Windows 注册表中配置 Schannel 协议
可以使用注册表细化控制你的客户端和/或服务器应用协商的协议。 你的应用的网络将遍历 Schannel(它是安全通道的另一个名称)。 通过配置 Schannel
,可以配置你的应用的行为。
从 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols
注册表项开始。 在该注册表项下,可以在集 TLS 1.2
、TLS 1.3
中创建任何子项。 在每个子项下,可以创建子项 Client
和/或 Server
。 在 Client
和 Server
下,可创建 DWORD 值 DisabledByDefault
(0 或 1)和 Enabled
(0 或 1)。
有关详细信息,请参阅:TLS 注册表设置 - Schannel
SCH_USE_STRONG_CRYPTO 标志
启用后(默认情况下,通过 AppContext
开关或 Windows 注册表),当应用启动到服务器的 TLS 连接时,.NET Framework 将使用 SCH_USE_STRONG_CRYPTO
标志。 .NET Framework 将标志传递到 Schannel
,以指示它禁用已知弱加密算法、密码套件和 TLS/SSL 协议版本(否则,可能会启用该协议以获得更好的互操作性)。 有关详细信息,请参见:
在显式使用 SecurityProtocolType 或 SslProtocols 的 Tls11
或 Tls12
枚举值时,SCH_USE_STRONG_CRYPTO
标志还会传递到客户端(传出)连接的 Schannel
。 标志 SCH_USE_STRONG_CRYPTO
仅用于应用程序在其中充当客户端角色的连接。 当应用程序通过配置计算机范围的 Schannel
注册表设置来充当服务器角色时,你可以禁用弱协议和算法。