Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HttpClient don't send SSL server_name extension #23231

Closed
daikoz opened this issue Aug 17, 2017 · 12 comments
Closed

HttpClient don't send SSL server_name extension #23231

daikoz opened this issue Aug 17, 2017 · 12 comments
Labels
area-System.Net.Http bug tenet-compatibility Incompatibility with previous versions or .NET Framework
Milestone

Comments

@daikoz
Copy link

daikoz commented Aug 17, 2017

Hi,

The aim is to test a web farm. DNS is configured with one IP (behind there are several servers) and redirect to one web server.

To test one server in web farm, in framework 4.6.2, I use with sample code:

          string host = "www.ebay.fr";

            IPHostEntry hostEntry;
            hostEntry = Dns.GetHostEntry(host);

            ///// HttpClient Test
            HttpClientHandler httpClientHandler = new HttpClientHandler();
            HttpClient client = new HttpClient(httpClientHandler);
            client.BaseAddress = new Uri("https://" + hostEntry.AddressList[0].ToString());
            client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible;" + DateTime.Now + " " + DateTime.Now.Millisecond + ")");
            client.DefaultRequestHeaders.Host = host;

            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, client.BaseAddress);
            request.Headers.Host = host;
            request.Headers.UserAgent.ParseAdd("Mozilla/5.0 (compatible;" + DateTime.Now + " " + DateTime.Now.Millisecond + ")");

            Task<HttpResponseMessage> task = client.SendAsync(request);
            task.Wait();
            HttpResponseMessage respones = task.Result;

With framework 4.6.2, it is work fine.

But in .net core 2, with a test on IIS server web server, the connexion close when web client try to negociate SSL.
Here I use "ebay" server but it is work on it. I don't found a IIS server on web. My web farm is not access from web.

I debug the connection with WireShark to see the network data:
With .net core2
image

With Framework 4.6.2
image

📌 I think the issue is with .net core, the extension server_name is not defined. IIS server should need known the certificat to take.
.net core 2 should define server_name from client.DefaultRequestHeaders.Host or request.Headers.Host (even if BaseAddress is an IP) ?

For more information:
https://idea.popcount.org/2012-06-16-dissecting-ssl-handshake/

TLS introduces a number of extensions. Most notably the server_name / Server Name Indication (SNI) extension is used to specify a remote host name. This allows the server to choose appropriate certificate based on the requested host name. With this extension one can host many SSL-enabled vhosts on a single IP address.

@davidsh
Copy link
Contributor

davidsh commented Aug 18, 2017

Is this on Windows or Linux?

@daikoz
Copy link
Author

daikoz commented Aug 18, 2017

On windows 10.

@davidsh
Copy link
Contributor

davidsh commented Sep 1, 2017

Please let us know the specific version of Windows 10. Please run 'CMD.EXE' window. And then type "ver". Let us know what the output is. Thx.

I tried your repro on Windows 10 Version 1703 (Microsoft Windows [Version 10.0.15063]) against the "www.ebay.fr" server. But I see the SNI in WireShark:

image

@daikoz
Copy link
Author

daikoz commented Sep 1, 2017

Hi,

You can find the project with test:
TestSSL.zip:

using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace TestSSL
{
    class Program
    {
        static void Main(string[] args)
        {
            string host = "www.google.fr";

            IPHostEntry hostEntry;
            hostEntry = Dns.GetHostEntry(host);

            // Accept SSL 
            HttpClientHandler handler = new HttpClientHandler();
            handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

            // Http Client
            HttpClient client = new HttpClient(handler);
            client.BaseAddress = new Uri("https://" + hostEntry.AddressList[0].ToString());
            client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (compatible;" + DateTime.Now + " " + DateTime.Now.Millisecond + ")");
            client.DefaultRequestHeaders.Host = host;

            // Call web site with IP. Host is define with full domain name of web site
            Task<HttpResponseMessage> task = client.GetAsync(client.BaseAddress);
            task.Wait();
            HttpResponseMessage response = task.Result;
        }
    }
}

I test again today, server_name is not defined on Windows but also on Debian.
The test define host to site name (for example: www.google.fr) but call web site with its IP adress.
With framework .net, server_name is define with host defined. But in .net core, not.

Windows: Microsoft Windows [Version 10.0.15063]
Debian 9.0: 4.9.0-3-amd64 GNU/Linux

Regards

[EDIT] Add full source from the zip file by @karelz

@daikoz daikoz closed this as completed Sep 1, 2017
@daikoz daikoz reopened this Sep 1, 2017
@geoffkizer
Copy link
Contributor

Maybe I'm missing something here, but it looks like you're using an IP address in your URL:

client.BaseAddress = new Uri("https://" + hostEntry.AddressList[0].ToString());

We can't send SNI info if you use an IP address. Use the DNS name instead.

@daikoz
Copy link
Author

daikoz commented Jan 7, 2018

No, like on framework .net, .net core should take host for SNI because you can have several host on same web server.

client.DefaultRequestHeaders.Host = host;

@karelz Do you fix it on 2.1 ?

@karelz
Copy link
Member

karelz commented Jan 7, 2018

@zokiad the issue was closed as "invalid" per closing comment, so it was not fixed.

I was able to reproduce the difference in behavior - .NET Core 2.0 does not send SNI in the repro above, while .NET Framework 4.7.1 does, reopening ...

@karelz karelz reopened this Jan 7, 2018
@davidsh
Copy link
Contributor

davidsh commented Jan 7, 2018

No, like on framework .net, .net core should take host for SNI because you can have several host on same web server.
client.DefaultRequestHeaders.Host = host;

The behavior of HTTP stack on Windows (non-UWP) is handled by native Windows WinHTTP.

I don't think WinHTTP will use the 'Host' header for SNI. It relies on the DNS name itself. We'll need to check into this.

@karelz
Copy link
Member

karelz commented Jan 17, 2018

Triage: It is important scenario. Given the limited interest so far (1 customer) and complications (it may be WinHTTP limitation), we won't address it in 2.1. ManagedHandler should be able to handle that (and will eventually become the default), so let's keep it opened.

@geoffkizer
Copy link
Contributor

I believe Stephen changed the managed handler to do this already. @stephentoub?

@stephentoub
Copy link
Member

stephentoub commented Jan 18, 2018

I believe Stephen changed the managed handler to do this already. @stephentoub?

dotnet/corefx@5ecea8f

@karelz
Copy link
Member

karelz commented Jan 18, 2018

OK, let's close it then. Eventually it will become default in .NET Core. Now it is opt-in.

@karelz karelz closed this as completed Jan 18, 2018
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net.Http bug tenet-compatibility Incompatibility with previous versions or .NET Framework
Projects
None yet
Development

No branches or pull requests

6 participants