109

I need to use TLS 1.2 to connect from my .NET web service to another that is going to force TLS 1.2. I found a resource that said .NET 4.6 uses TLS 1.2 by default so that sounded like the easiest solution. I updated the .NET framework on the server and restarted. In IIS I tried to make an application pool using .NET 4.6 but 4.0 was the only option. Then I found something that said it would still say 4.0 because 4.6 is an "in place" update to .NET 4.0. So I thought maybe I was done. However on an error page that I got for unrelated reasons, it said Microsoft .NET Framework Version:4.0.30319 so it seems I have not successfully upgraded. Any pointers on how to make sure my application pool is using .NET 4.6, or more generally how to enable TLS 1.2?

nasch
  • 4,972
  • 6
  • 26
  • 45

6 Answers6

155

We actually just upgraded a .NET web service to 4.6 to allow TLS 1.2.

What Artem is saying were the first steps we've done. We recompiled the framework of the web service to 4.6 and we tried change the registry key to enable TLS 1.2, although this didn't work: the connection was still in TLS 1.0. Also, we didn't want to disallow SLL 3.0, TLS 1.0 or TLS 1.1 on the machine: other web services could be using this; we rolled-back our changes on the registry.

We actually changed the Web.Config files to tell IIS: "hey, run me in 4.6 please".

Here's the changes we added in the web.config + recompilation in .NET 4.6:

<system.web>
    <compilation targetFramework="4.6"/> <!-- Changed framework 4.0 to 4.6 -->

    <!--Added this httpRuntime -->
    <httpRuntime targetFramework="4.6" />

    <authentication mode="Windows"/>
    <pages controlRenderingCompatibilityVersion="4.0"/>
</system.web>

And the connection changed to TLS 1.2, because IIS is now running the web service in 4.6 (told explicitly) and 4.6 is using TLS 1.2 by default.

Michael
  • 5,910
  • 4
  • 52
  • 74
Etienne Faucher
  • 2,321
  • 1
  • 16
  • 20
  • 3
    Here's the documentation we used for research: [HTTPRuntime](https://blogs.msdn.microsoft.com/webdev/2012/11/19/all-about-httpruntime-targetframework/), [RenderingCompatibility](https://msdn.microsoft.com/en-us/library/system.web.ui.control.renderingcompatibility(v=vs.110).aspx) – Etienne Faucher Aug 01 '17 at 16:18
  • I made those changes to my web.config, rebuilt, deployed, and I'm getting `System.Net.WebException: The request failed with an empty response.` I don't know if it's from my end or a problem on the other side. Any idea how to verify that I'm using TLS 1.2? – nasch Aug 02 '17 at 16:40
  • You could use a network protocol analyser, like [Wireshark](https://www.wireshark.org/) to verify the status of your connection. – Etienne Faucher Aug 02 '17 at 17:32
  • 1
    I figured it out - I wasn't requesting HTTPS. After I fixed that, it worked. – nasch Aug 02 '17 at 19:30
  • @EtienneFaucher - I am using .Net 4.5. So i make the change change in code like : SecurityProtocol = TLS | TLS1 | TLS2 or SecurityProtocol = TLS2 ?? which one is correct to make it TLS compliant. – SunilA Sep 15 '17 at 02:32
  • @SunilA Both should be ok. You are accepting TLS 1.2 in both cases. In the second case, it should not accept TLS 1.0/TLS1.1 as protocol for your connections. In our case, we didn't change any code; we only changed the application framework. – Etienne Faucher Sep 15 '17 at 18:58
  • 5
    Changing compilation to 4.6 and adding the httpRuntime 4.6 was enough in our case, thanks for the solution! – krilovich Jan 05 '18 at 17:16
  • 2
    This is totally the right answer. Just went through this recently. Here's a blog post about it: http://blog.thelevelup.com/pci-security-is-your-restaurant-ready/ and a GitHub project that does this: https://github.com/TheLevelUp/pos-tls-patcher – user24601 Mar 08 '18 at 03:24
  • THANK YOU! -- In my case I had two programs side by side, both being compiled with and theoretically using version 4.6, and one worked while the other one failed. I had the epiphany that one was a web site using old web technologies and thus may be using an older version by default, I found this answer and VOILA. Thanks for including the other ways to select the framework -- peace of mind since I'm rendering with 3.5! – Gerard ONeill Jun 01 '18 at 15:35
  • All these configs were available in my project config file and it used to tls as a default version but I want to use tls12. Then I added System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; so it forces the service to use tls12 version at the end. – Alex Jun 07 '18 at 21:07
  • 2
    https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls – spikej Aug 08 '18 at 18:36
  • Above URL by spikej => "Transport Layer Security (TLS) best practices with the .NET Framework" – hB0 Mar 12 '19 at 14:05
  • 1
    I logged in just to upvote @user24601 - the link and suggestion to use the TLS Patcher was the answer for me - forget trying to configure your registry manually. Install this and it does the trick! Thanks - maybe my hair will grow back now. – Brian Jun 05 '19 at 14:50
  • 1
    I feel obligated to point out that the best solution is to target .NET 4.7 — if 4.7 is supported on your particular platform and upgrading .NET is a real option. – user24601 Jun 05 '19 at 14:53
  • You saved my day! Upgrading target to .NET 4.7 solved it. Thanks – aguedob Dec 19 '19 at 09:26
  • PowerBI Embeded requires TLS 1.2 now - the above solution worked for me to force a 4.5 runtime to a 4.6 runtime. I had to cross the 4.6 runtime level to get the TLS 1.2 defaults to work where I needed them to. – Sql Surfer Jun 24 '20 at 04:29
  • +1 but just needed to add that I had to upgrade to 4.8 to make my (4.6) app be able to use integration NuGet packages with third-party servers. – EvilDr Sep 04 '20 at 08:57
104

Add the following code before you instantiate your web service client:

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

Or for backward compatibility with TLS 1.1 and prior:

System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; 
John Wu
  • 44,075
  • 6
  • 37
  • 69
  • 2
    Yeah I'm already doing that, but the error message still indicates .NET 4.0. – nasch Jul 29 '17 at 18:54
  • 13
    That is your CLR version. The .Net CLR has two versions, 2.0 and 4.0. In IIS you specify the CLR version, not the Framework version. IIS won't tell you .Net 4.6 because it doesn't care about that. If you compiled using 4.6, then you are using 4.6. –  Aug 01 '17 at 14:20
  • 4
    TLS 1.2 is supported from .NET 4.5 onwards – Gilberto Alexandre Jul 30 '18 at 19:29
  • And for VB.NET: System.Net.ServicePointManager.SecurityProtocol = DirectCast(3072, System.Net.SecurityProtocolType) – deebs Aug 08 '18 at 20:28
  • @JohnWu: I believe if we write this command in a main program of a project then all web request withing same exe will use the specified protocol. Correct me if it is the otherwise. – Itz.Irshad Sep 06 '18 at 06:27
  • @Itz.Irshad The protocol is negotiated. The setting enables it. – John Wu Sep 06 '18 at 07:32
  • @JohnWu: Consider the specified protocol is enabled on server. The client used a winform application to download data after specifying the protocol as suggested. Then every web request will use the same protocol. Right ? – Itz.Irshad Sep 06 '18 at 07:56
  • 6
    In this case, |= is superior to just =. They're binary flags, don't overwrite everything else unnecessarily. – Izzy Sep 06 '18 at 09:09
  • 2
    @JohnWu - please note Izzy's comment above. Your code tells .NET to explicitly ONLY use TLS 1.2 when connecting to HTTPS resources. I.e. if a server only had TLS 1.1, your code would stop it from connecting since it's only using TLS 1.2. You should use |= to tell your code "try to use TLS 1.2 as an option too" when the client and server negotiate which protocol to use. – Don Cheadle Nov 05 '18 at 01:00
  • This is the solution when using the stock `System.Net.Mail.SmtpClient` and the mail server requires TLS1.2. You need to tell the `ServicePointManager.SecurityProtocol` to use `Tls12`. – David Dombrowsky Aug 05 '20 at 16:08
31

if you're using .Net earlier than 4.5 you wont have Tls12 in the enum so state is explicitly mentioned here

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
bresleveloper
  • 5,430
  • 3
  • 31
  • 45
  • Thank you. This helped me out. For anyone researching I was attempting to create a new folder in AzureFileStorage: fileDirectory.CreateIfNotExists(); The fileDirectory is a CloudFileDirectory object. I simply placed ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; before that and it worked like a charm. Thanks again. – SuperVillainPresident Dec 13 '20 at 20:32
17

Three steps needed:

  1. Explicitly mark SSL2.0, TLS1.0, TLS1.1 as forbidden on your server machine, by adding Enabled=0 and DisabledByDefault=1 to your registry (the full path is HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols). See screen for details registry

  2. Explicitly enable TLS1.2 by following the steps from 1. Just use Enabled=1 and DisabledByDefault=0 respectively.

NOTE: verify server version: Windows Server 2003 does not support the TLS 1.2 protocol

  1. Enable TLS1.2 only on app level, like @John Wu suggested above.

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

Hope this guide helps.

UPDATE As @Subbu mentioned: Official guide

Artem
  • 1,826
  • 1
  • 19
  • 27
6

For me below worked:

Step 1: Downloaded and installed the web Installer exe from https://www.microsoft.com/en-us/download/details.aspx?id=48137 on the application server. Rebooted the application server after installation was completed.

Step 2: Added below changes in the web.config

<system.web>
    <compilation targetFramework="4.6"/> <!-- Changed framework 4.0 to 4.6 -->
    <!--Added this httpRuntime -->
    <httpRuntime targetFramework="4.6" />
</system.web>

Step 3: After completing step 1 and 2, it gave an error, "WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping for 'jquery'. Please add a ScriptResourceMapping named jquery(case-sensitive)" and to resolve this error, I added below key in appsettings in my web.config file

<appSettings>
      <add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
</appSettings>
KRM
  • 965
  • 1
  • 10
  • 24
0

PowerBI Embedded requires TLS 1.2.

The answer above by Etienne Faucher is your solution. quick link to above answer... quick link to above answer... ( https://stackoverflow.com/a/45442874 )

PowerBI Requires TLS 1.2 June 2020 - This Is your Answer - Consider Forcing your IIS runtime to get up to 4.6 to force the default TLS 1.2 behavior you are looking for from the framework. The above answer gives you a config change only solution.

Symptoms: Forced Closed Rejected TCP/IP Connection to Microsoft PowerBI Embedded that just shows up all of a sudden across your systems.

These PowerBI Calls just stop working with a Hard TCP/IP Close error like a firewall would block a connection. Usually the auth steps work - it is when you hit the service for specific workspace and report id's that it fails.

This is the 2020 note from Microsoft PowerBI about TLS 1.2 required

PowerBIClient

methods that show this problem

GetReportsInGroupAsync GetReportsInGroupAsAdminAsync GetReportsAsync GetReportsAsAdminAsync Microsoft.PowerBI.Api HttpClientHandler Force TLS 1.1 TLS 1.2

Search Error Terms to help people find this: System.Net.Http.HttpRequestException: An error occurred while sending the request System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

Sql Surfer
  • 1,139
  • 7
  • 23