通过 App.config 为 System.Net.HttpWebRequest 指定 SSL/TLS

Specifying SSL/TLS for System.Net.HttpWebRequest through App.config

我需要 POST JSON 数据到 TLS 1.2 端点。我希望在 App.config 中指定 SecurityProtocol 而不是在源代码中进行硬编码,并且不想将机器的注册表设置为禁用 TLS 1.1。

如果您不指定 SecurityProtocol,则使用基础 OS 协议,但它们似乎默认为最不安全的而不是最安全的。因为我有来自机器的多个服务 运行 我不能将 OS 设置为只使用 TLS1.2,但我仍然希望这个特定的客户端使用 TLS 1.2,当 TLS 1.3 出来时能够通过特定于应用程序的配置对其进行修改。

这个问题解释了如何通过代码来做到这一点:

这个问题解释了如何通过整个机器的注册表设置来做到这一点:Are there .NET implementation of TLS 1.2?

// this is what I want to avoid
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocol.Tls12;

System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url);

using (System.IO.StreamWriter sw = new System.IO.StreamWriter(request.GetRequestStream()))
{
    sw.write(json);
}

System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
using System.IO.StreamReader sr = new System.IO.StreamReader(response.GetResponseStream()))
{
    content = sr.ReadToEnd();
}

目前我的 App.config 中没有此客户的任何内容,但这是我想更改的内容。

我发现 system.serviceModel 中有一个 sslStreamSecurity 元素,但我相信这是针对 ServiceReferences 的,而不是普通的 HttpWebRequest。我相信 system.net 涵盖了这一点,但我找不到等效项。

<system.serviceModel>
  <bindings>
    <customBinding>
      <binding name="myBinding">
        <sslStreamSecurity sslProtocls="Tls12">
      </binding>
    </customBinding>
  </bindings>
  <client>
    <endpoint address="https://myserver.com" binding="customBinding" bindingConfiguration="myBinding" name="myEndpoint" />
  </client>
</system.ServiceModel>

我对使用 HttpWebRequest/HttpWebResponse 以外的东西持开放态度,但不想安装第三方软件包。我从 System.Net.Http.HttpClient 开始走这条路,它看起来比 HttpWebRequest 更新,但很快 运行 遇到了同样的问题。

现在我在 App.config 中放置了一个整数值,指定要设置 System.Net.ServicePointManager.SecurityProtocol 的枚举值。我仍然认为可能有更优雅的方式来做到这一点,并期待其他答案。

引导我朝这个方向发展
int securityProtocol = Convert.ToInt32(ConfigurationManager.AppSettings["SecurityProtocol"]);

try
{
    System.Net.ServicePointManager.SecurityProtocol = (System.Net.SecurityProtocolType)securityProtocol;
}
catch(Exception ex)
{
    Console.WriteLine("Could not setup SecurityProtocol. Try a different integer value: " + ex.Message);
    foreach (System.Net.SecurityProtocolType protocolType in Enum.GetValues(typeof(System.Net.SecurityProtocolType)))
    {
        Console.WriteLine(string.Foramt("SecurityProtocol: {0} - {1}", protocolType.ToString(), (int)protocolType));
    }
}

App.config:

<appSettings>
    <add key="SecurityProtocol" value="3072" />
</appSettings>

示例使用协议名称而不是整数代码。

string securityProtocol = ConfigurationManager.AppSettings["SecurityProtocol"].ToString();

try
{
    System.Net.ServicePointManager.SecurityProtocol = (System.Net.SecurityProtocolType)Enum.Parse(typeof(System.Net.SecurityProtocolType), securityProtocol);
}
catch (Exception ex)
{
    Console.WriteLine("Could not setup SecurityProtocol. Try a different integer value: " + ex.Message);
    foreach (System.Net.SecurityProtocolType protocolType in Enum.GetValues(typeof(System.Net.SecurityProtocolType)))
    {
        Console.WriteLine(string.Foramt("SecurityProtocol: {0} - {1}", protocolType.ToString(), (int)protocolType));
    }
}

对于App.Config

<appSettings>
    <add key="SecurityProtocol" value="Tls12" />
</appSettings>

只要您 运行 在 ≥.net-4.6 上,就可以通过编辑其 app.config 来更改针对 <.net-4.6 的应用程序的 TLS 设置而无需重新编译它.这记录在 “Transport Layer Security (TLS) best practices with the .NET Framework”.

当 Microsoft 开发 .net-4.6 作为 .net-4.5 的就地替代品时,他们希望进行行为更改,包括错误修复、安全改进等。但他们不想破坏针对 .net 的应用程序-4.5 依赖于旧的行为——甚至是有缺陷的行为(旧代码依赖有缺陷的行为是很常见的,微软的 .net 团队关心到为了兼容性而有目的地保留缺陷的程度)。为此,从 .net-4.6 开始并继续到更高版本,每个预计会导致兼容性问题的新行为更改都放在一个开关后面,该开关启用旧行为并默认为 true。在编译时,目标框架存储在程序集中。当运行时加载入口点的程序集时,它会检查目标版本,然后自动为目标 .net 版本预设其兼容性开关。

如果您无法重新定位或重新编译您的应用程序,您可以通过在通常命名为 [=15= 的 app.config 中添加或编辑 <AppContextSwitchOverrides/> 来手动指定这些兼容性开关的值].开关 DontEnableSystemDefaultTlsVersions 是在 .net-4.7 中添加的,它支持使用系统提供的 TLS 策略。 .net-4.6 中添加了开关 DontEnableSchUseStrongCrypto,它增加了对 TLS 1.2 的支持。

<?xml version="1.0"?>
<configuration>
  <runtime>
    <!--
      Support connecting to servers which require modern TLS protocols.

      DontEnableSystemDefaultTlsVersions=false is sufficient if running on ≥.net-4.7
      which supports using the system-provided TLS versions/policies.
      DontEnableSchUseStrongCrypto is required if running on .net-4.6 which defaults
      to newer versions of TLS but doesn’t support following system updates/policies.
     -->
    <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=false;Switch.System.Net.DontEnableSchUseStrongCrypto=false"/>
  </runtime>
</configuration>