来自C#的服务器名称指示

woo*_*ain 7 .net c# ssl libcurl sni

据我所知,.NET中似乎存在很大的局限性,因为没有办法使用C#和.NET来建立使用服务器名称指示(SNI)的TLS连接.我错过了什么或者我的理解是否正确?

有没有人知道我是否以及如何使用OpenSSL.NET,libcurl.NET或其他第三方.NET库进行SNI连接?一些示例代码将非常感谢.

Tik*_*all 5

在我的 .Net 4.5 项目中,以下对于使用 SNI 的服务器失败:

var url = "https://www.somesite.com";
System.Net.WebClient client = new System.Net.WebClient();
client.Encoding = Encoding.UTF8;
var data = client.DownloadString(url);
Run Code Online (Sandbox Code Playgroud)

但如果通过以下前缀明确指定 TLS1.2,它会起作用:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Run Code Online (Sandbox Code Playgroud)

这同样适用于 webrequest:

WebRequest request = WebRequest.Create("https://www.somesite.com");
Run Code Online (Sandbox Code Playgroud)

和 HttpRequestMessage:

var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
Run Code Online (Sandbox Code Playgroud)

他们都需要将协议明确设置为 TLS 1.2 才能与 SNI 服务器一起使用(这可能在较新的 .Net 版本中有所改变)


小智 2

这是一篇相当老的帖子,但这个答案仍然可能对某些人有所帮助,至少它花了我几天的时间。

默认情况下,.NET Framework 支持服务器名称指示。(在 4.5.1 上测试过,但我想至少对于 .NET 4.5+ 来说是一样的)

一个简短的例子:

HttpResponseMessage response;
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");

var handler = new HttpClientHandler
{
    CookieContainer = new CookieContainer()
};
using (var client = new HttpClient(handler))
{
    response = client.SendAsync(httpRequestMessage).Result;
}
Run Code Online (Sandbox Code Playgroud)

这是在 C# 中创建 GET 请求的非常标准的方法。您将看到,在我的例子中,此示例确实使用带有 SNI 的 TLS 1.2 运行。如果您使用 Wireshark 查看发送的实际包,您将看到客户端问候,其中服务器名称指示设置为 www.google.com。

我们遇到的一个问题:SNI 标记是由 .NET Framework(或 Windows 的 Schannel,不确定)根据 HttpRequestMessage 构造函数中传递的 URL 设置的。如果您知道根据某个 URL(例如https://www.google.com)初始化请求,然后切换RequestUri Host标头,SNI 标记仍将根据原始 url URL 创建例如,如果您传递请求并将所有原始标头重新映射到新创建的请求,则可能会出现这种情况。