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

时间:2013-11-14 06:40:17

标签: c# .net ssl libcurl sni

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

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

2 个答案:

答案 0 :(得分:3)

在我的.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);

但是如果通过以下方式明确指定TLS1.2,它就可以工作:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

同样适用于webrequest:

WebRequest request = WebRequest.Create("https://www.somesite.com");

和HttpRequestMessage:

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

他们都需要将协议显式设置为TLS 1.2才能与SNI服务器一起使用(在新的.Net版本中可能已更改)

答案 1 :(得分:1)

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

.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;
}

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

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