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

Car*_*ans 6 .net app-config webclient httpwebrequest dotnet-httpclient

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

如果未指定SecurityProtocol,则使用底层OS协议,但默认情况下它们似乎是最不安全的,而不是最安全的。因为我有从计算机运行的多种服务,所以不能将操作系统设置为仅使用TLS1.2,但是我仍然希望该特定客户端使用TLS 1.2,并且当TLS 1.3推出时,可以通过应用程序特定的配置对其进行修改。

这个问题解释了如何通过代码做到这一点:如何为WebClient类指定SSL协议

这个问题说明了如何通过整个计算机的注册表设置来做到这一点:是否存在TLS 1.2的.NET实现?

// 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();
}
Run Code Online (Sandbox Code Playgroud)

我的客户端当前在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>
Run Code Online (Sandbox Code Playgroud)

我很愿意使用HttpWebRequest / HttpWebResponse以外的其他方式,但希望远离安装第三方软件包。我开始寻找一条System.Net.Http.HttpClient比HttpWebRequest更新的路径,但很快遇到了同样的问题。

bin*_*nki 9

app.config只要您在 ?.net-4.6 上运行,就可以更改面向 <.net-4.6 的应用程序的 TLS 设置,而无需通过编辑它来重新编译它。这在“.NET Framework 的传输层安全性 (TLS) 最佳实践”中有所记录。

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

如果不能重新定位或重新编译应用程序,您可以手动添加或编辑指定这些兼容性开关的价值<AppContextSwitchOverrides/>app.config通常被命名«ExecutableName».exe.config。该开关DontEnableSystemDefaultTlsVersions是在 .net-4.7 中添加的,它支持使用系统提供的 TLS 策略。该开关DontEnableSchUseStrongCrypto是在 .net-4.6 中添加的,它增加了对 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>
Run Code Online (Sandbox Code Playgroud)


Car*_*ans 2

现在,我已在 App.config 中放入一个整数值,该值指定要设置的枚举值System.Net.ServicePointManager.SecurityProtocol。我仍然认为可能有一种更优雅的方法来做到这一点并期待其他答案。/sf/answers/2472773341/引导我朝这个方向发展

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

应用程序配置:

<appSettings>
    <add key="SecurityProtocol" value="3072" />
</appSettings>
Run Code Online (Sandbox Code Playgroud)