0

I have created an application with .net Framework 4.8.1, it works well on the pc where it was developed (computer under windows 11) but has a different behavior on two other computers under windows 10 freshly installed and updated.

Part I = The context =

My application sends an http request with http2 to retrieve a token from a remote CloudFlare server.

Here is the request I send to the server:

{Method: POST, RequestUri: 'https://this.is.confidential/json/gov/v10/Api/CreateApiKey', Version: 2.0, Content: System.Net.Http.StringContent, Headers:
{
  Content-Type: text/plain; charset=utf-8
}}

On the computer running Windows 11, the server response is as follows:

{StatusCode: 200, ReasonPhrase: '', Version: 2.0, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers:
{
  Cache-Control: no-store, no-cache
  Date: Tue, 13 Dec 2022 19:37:43 GMT
  Server: cloudflare
  Set-Cookie: __cf_bm=W5wDtxsixycI1_5G5fdgdfJGkVCX5nT9tzG8-1670960263-0-AfqDRz1MMF67L/ntDOShg3Jz3GZxMo/UtCYReTfDIJl1g0vQ/MfeVa5C8/PxQLtucWoYvV5nYGEyyuN/r19aWWo=; path=/; expires=Tue, 13-Dec-22 20:07:43 GMT; domain=.thisisconfidential.com; HttpOnly; Secure; SameSite=None
  Vary: Accept-Encoding
  access-control-allow-origin: *
  x-duration: 33.200026
  cf-cache-status: DYNAMIC
  cf-ray: 779127ecadedf11c-CDG
  Content-Type: application/json
}}

On the computer running Windows 10, the server response is as follows:

{StatusCode: 403, ReasonPhrase: '', Version: 2.0, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers:
{
  Cache-Control: no-store, must-revalidate, no-cache, max-age=0, private, post-check=0, pre-check=0
  Date: Tue, 13 Dec 2022 13:18:28 GMT
  Server: cloudflare
  Set-Cookie: __cf_bm=oKXtpXuiUmH5MeEA8n67RTG33dfZhv5Th5c3ZX0PAUSw1oA-1670937508-0-AX+aH9+MYxwNqOdbMZCmhg35ByjwgaTmtJdditJ7K1xEU1ex7au/PyiJ4JbCImQvICHQPcr+QJijZSeYfKme3/o=; path=/; expires=Tue, 13-Dec-22 13:48:28 GMT; domain=.thisisconfidential.com; HttpOnly; Secure; SameSite=None
  x-frame-options: SAMEORIGIN
  referrer-policy: same-origin
  cf-ray: 778efc668ed6d07b-CDG
  Content-Length: 16
  Content-Type: text/plain; charset=UTF-8
  Expires: Thu, 01 Jan 1970 00:00:01 GMT
}}

Part II = The code =

To use http2 in .NET 4.8.1 i use a HttpHandler custom class:

Imports System.Net.Http

Public Class Http2CustomHandler : Inherits WinHttpHandler
    Protected Overrides Function SendAsync(request As HttpRequestMessage, cancellationToken As Threading.CancellationToken) As Task(Of HttpResponseMessage)
        request.Version = New Version("2.0")
        Return MyBase.SendAsync(request, cancellationToken)
    End Function
End Class

And I call it when I send the request:

            Using wclient As New HttpClient(New Http2CustomHandler())
                Dim url As String = "https://this.is.confidential.com/json/gov/v10/Api/CreateApiKey"
                With wclient
                    .BaseAddress = New Uri(url)
                    .DefaultRequestHeaders.UserAgent.Add(New Headers.ProductInfoHeaderValue("govAgent", "3.6.15"))
                    .DefaultRequestHeaders.Accept.Clear()
                    .DefaultRequestHeaders.Accept.Add(New Headers.MediaTypeWithQualityHeaderValue("text/plain"))
                End With


                Dim req = New HttpRequestMessage With {
                .RequestUri = New Uri("https://this.is.confidential.com/json/gov/v10/Api/CreateApiKey"),
                .Method = HttpMethod.Post,
                .Content = New StringContent($"login={login}&password={password}&gov={gov}&long_life_token=true", Encoding.UTF8, "text/plain")
            }

                Dim response As HttpResponseMessage = Await wclient.SendAsync(req)
                Dim jsonString = response.Content.ReadAsStringAsync().Result

Part III = some informations =

To launch my application on Windows 10 computers I copied the Release folder containing all the useful DLLs. I also published my code and installed my application on computers running Windows 10.

I also moved my VB net project on the other computers to test to compile and run and I have the same problem, the request fails systematically.

My windows 11 and 10 are up to date and have all .NET 4.8.1 installed.

I'm going crazy, I don't understand what the problem is.

Thank you.

UPDATE : There is actually a bug on windows 10 and .net framework 4.8/4.8.1 combined with WinHttpHandler. It does not work with 2.0 http version BUT if you put 3.0 http version it works with cloudflare WAF !! That's stupid !

  • **401 Unauthorized** *The HyperText Transfer Protocol (HTTP) 401 Unauthorized response status code indicates that the client request has not been completed because it lacks valid authentication credentials for the requested resource. This status code is sent with an **HTTP WWW-Authenticate** response header that contains information on how the client can request for the resource again after prompting the user for authentication credentials.* – Lundt Dec 14 '22 at 00:15
  • The following may be helpful: [Protocols in TLS/SSL (Schannel SSP)](https://learn.microsoft.com/en-us/windows/win32/secauthn/protocols-in-tls-ssl--schannel-ssp-#tls-protocol-version-support) and [Transport Layer Security (TLS) best practices with the .NET Framework](https://learn.microsoft.com/en-us/dotnet/framework/network-programming/tls) – Tu deschizi eu inchid Dec 14 '22 at 03:12
  • The following may be helpful: [How to: Configure network tracing](https://learn.microsoft.com/en-us/dotnet/framework/network-programming/how-to-configure-network-tracing#configure-network-tracing). Aso see [HTTP/2 on IIS](https://learn.microsoft.com/en-us/iis/get-started/whats-new-in-iis-10/http2-on-iis). – Tu deschizi eu inchid Dec 14 '22 at 06:20
  • @Lundt the response code is 403 not 401. 403 is client side problem. – SuperJudeFruit Dec 14 '22 at 09:36
  • @user09938 Thank you for these links, they are very useful, from what I see my versions of Windows respect all the requirements. I will try to configure the network tracing but the information on the http2 on IIS is not very relevant because I know that the server is well configured (it works with postman for example) – SuperJudeFruit Dec 14 '22 at 09:45
  • Guess it is time to clean the dust off my monitor. – Lundt Dec 14 '22 at 19:40
  • Unfortunately this is not a problem in the code, I checked with WireShark and Fiddler the requests and they are good. I also checked with Postman and the request is working on windows 10 computers ! I tried everything and I'm really fed up, I don't understand the difference between the Postman request and mine especially since it works on windows 11 on the same network ! I really reached my limits. I think CloudFlare detect something i cant. – SuperJudeFruit Dec 15 '22 at 19:25

1 Answers1

0

The following is not an answer but may be helpful.

Configure tracing:

If your application doesn't have a .config file (ex: app.config, Web.config), then add one. In the .config file, add the following to <configuration>...</configuration>. See How to: Configure network tracing for more information.

    <system.diagnostics>
        <sources>
            <source name="System.Net">
                <listeners>
                    <add name="System.Net"/>
                </listeners>
            </source>
            <source name="System.Net.Cache">
                <listeners>
                    <add name="System.Net"/>
                </listeners>
            </source>
            <source name="System.Net.Http">
                <listeners>
                    <add name="System.Net"/>
                </listeners>
            </source>
            <source name="System.Net.Sockets">
                <listeners>
                    <add name="System.Net"/>
                </listeners>
            </source>
            <source name="System.Net.WebSockets">
                <listeners>
                    <add name="System.Net"/>
                </listeners>
            </source>
        </sources>
        <switches>
            <add name="System.Net" value="Verbose"/>
            <add name="System.Net.Cache" value="Verbose"/>
            <add name="System.Net.Http" value="Verbose"/>
            <add name="System.Net.Sockets" value="Verbose"/>
            <add name="System.Net.WebSockets" value="Verbose"/>
        </switches>
        <sharedListeners>
            <add name="System.Net"
              type="System.Diagnostics.TextWriterTraceListener"
              initializeData="network.log"
               traceOutputOptions="ProcessId, DateTime"
      />
        </sharedListeners>
        <trace autoflush="true"/>
    </system.diagnostics>

Note: initializeData specifies the log file name. To specify a fully-qualified log file name, escape each of the backslashes by adding an extra one initializeData="C:\\Temp\\network.log"


Add the following Imports:

  • Imports System.Net
  • Imports System.Net.Http
  • Imports System.Text
  • Imports System.Reflection
  • Imports System.Security.Authentication

GetTLSVersion:

Note: The following code is converted to VB.NET from this post.

Public Async Function GetTLSVersion(url As String) As Task(Of String)

    Using client As HttpClient = New HttpClient()
        Using response As HttpResponseMessage = Await client.GetAsync(url)
            If TypeOf (response.Content) Is StreamContent Then
                Dim webExceptionWrapperStream = GetField(response.Content, "content")
                Dim connectStream = GetBaseField(webExceptionWrapperStream, "innerStream")
                Dim connection = GetProperty(connectStream, "Connection")
                Dim tlsStream = GetProperty(connection, "NetworkStream")
                Dim state = GetField(tlsStream, "m_Worker")
                Dim protocol As SslProtocols = CType(GetProperty(state, "SslProtocol"), SslProtocols)
                Return protocol.ToString()
            End If
        End Using

        Return String.Empty
    End Using
End Function

Private Function GetBaseField(obj As Object, field As String) As Object
    Return obj?.GetType()?.BaseType?.GetField(field, BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public)?.GetValue(obj)
End Function

Private Function GetField(obj As Object, field As String) As Object
    Return obj?.GetType()?.GetField(field, BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public)?.GetValue(obj)
End Function

Private Function GetProperty(obj As Object, prop As String) As Object
    Return obj?.GetType()?.GetProperty(prop, BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public)?.GetValue(obj)
End Function

Usage

Private Async Sub btnRun_Click(sender As Object, e As EventArgs) Handles btnRun.Click
        
    Dim tlsVersion As String = Await GetTLSVersion("https://www.bing.com")
    Debug.WriteLine($"TLS version: {tlsVersion}{Environment.NewLine}")
End Sub

Update:

It seems that TLS 1.3 can be enabled in Windows 10.

Create a full backup of your computer (recommended)

Create a restore point

  • Open Control Panel
  • Select View by: Small icons
  • Click System
  • On left side, click System protection
  • If protection isn't turned on for the C:, then click Configure to turn it on. Select desired size and click OK.
  • Click Create to create a restore point
  • Enter desired name for restore point
  • Click Create

Copy the code/text below to a file that ends in .reg (ex: EnableTls13.reg).

  • Open you're favorite text editor (ex: Notepad)
  • Copy the code/text below
  • Save file with a ".reg" extension (ex: EnableTls13.reg). Alternatively, save with a ".txt" extension. Then right-click the file and rename it so that it has a ".reg" extension.

Win 10 (64-bit):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3]

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters]
"EnableHttp3"=dword:00000001

Then double click the file to add the entries to the registry. Alternatively, add each of the registry entries to the registry using regedit.

Reboot the computer.

Resources:

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24
  • Thank you for your very complete answer! Here is the version of TLs that is returned: TLS version: Tls12 But in the logs I see that it is not http2 that is used to send the request but http 1. Or it just logs the sendAsync from the beginning and not the whole thing? Because in my debug on the variables I have http 2. – SuperJudeFruit Dec 14 '22 at 22:56
  • Unfortunately this is not a problem in the code, I checked with WireShark and Fiddler the requests and they are good. I also checked with Postman and the request is working on windows 10 computers ! I tried everything and I'm really fed up, I don't understand the difference between the Postman request and mine especially since it works on windows 11 ! I really reached my limits – SuperJudeFruit Dec 15 '22 at 19:25