How do you check the Negotiated TLS Handshake from the Server?
Asked Answered
S

1

7

If I have a dozen endpoints, and my WebAPI Service is configured for TLS 1.1 and TLS 1.2, how do I check each incoming endpoint request to see which version was negotiated?

So if a consumer of my endpoints currently only supports TLS 1.0 and TLS 1.1, they'll (obviously?) negotiate a TLS 1.1 handshake. But if a different consumer supports TLS 1.2 and TLS 1.3, they'll (obviously?) negotiate a TLS 1.2 handshake.

I want to track all of my consumers to see what handshakes are being negotiated. How do I do that per-request?

Summation answered 24/11, 2018 at 19:25 Comment(7)
I posted some informations on this matter here: Which TLS version was negotiated?. This, of course, applies to the client-side of the world, I'm not sure it can be useful here. But maybe you can find something interesting among the notes.Unrounded
@Unrounded Great info. There were some key terms in there that might have lead to something, but additional searching didn't result in anything substantial. I'm sure I'll use it more in my research, but for now, it is very one-sided. :)Summation
According to This similar Question and Answer, my question is pretty close to duplicate and the answer is You Can't. I hope somebody comes along and says otherwise, or maybe even in .NET CORE. But even that looks like a resounding No. Boooo.Summation
Well, you're right. This is something that is really missing in the managed implementations of the Network/Ssl streams on the higher layers (TCP knows everything). On both sides. Anyway, since I'm still keeping an eye out on this matter, I'm bookmarking your question and if something comes up I'll let you know.Unrounded
Not a great answer but ... if you can support multiple endpoints you can configure them separately. Why do you want to know which version of TLS is in use? Seems like you would document your security requirements and update them as necessary based on your business needs.Brettbretz
@NoRefundsNoReturns Logging, Education and Troubleshooting. I don't know of any business logic in the code that would change based on the information. But when dealing with a large number of integrations and consumers on the Front and Back Boundaries of my MicroService, I want that additional information. Specifically because Security Requirements are changing rapidly recently.Summation
@Unrounded you may like the updated answer below.Brettbretz
B
6

If you are using IIS it looks like you can add some extended logging to your IIS logs.

https://cloudblogs.microsoft.com/microsoftsecure/2017/09/07/new-iis-functionality-to-help-identify-weak-tls-usage/

plagiarizing ... er ... quoting for posterity:

To enable this new functionality, these four server variables need to be configured as the sources of the custom fields in IIS applicationHost.config. The custom logging can be configured on either server level or site level. Here is a sample site-level configuration:

<site name="Default Web Site" id="1" serverAutoStart="true">
 <application path="/">
 <virtualDirectory path="/" physicalPath="C:\inetpub\wwwroot" />
 </application>
 <bindings>
 <binding protocol="https" bindingInformation="*:443:" />
 </bindings>
 <logFile>
 <customFields>
 <clear />
<add logFieldName="crypt-protocol" sourceName="CRYPT_PROTOCOL" sourceType="ServerVariable" />
<add logFieldName="crypt-cipher" sourceName="CRYPT_CIPHER_ALG_ID" sourceType="ServerVariable" />
<add logFieldName="crypt-hash" sourceName="CRYPT_HASH_ALG_ID" sourceType="ServerVariable" />
<add logFieldName="crypt-keyexchange" sourceName="CRYPT_KEYEXCHANGE_ALG_ID" sourceType="ServerVariable" />
 </customFields>
 </logFile>
 </site>

Each SSL info field is a hexadecimal number that maps to either a secure protocol version or cipher suite algorithm. For an HTTP plain-text request, all four fields will be logged as ‘-‘.

Me again:

It looks like CRYPT_PROTOCOL can be 400 for TLS1.2, 40 for TLS 1.0, 10 for SSLv3 in the IIS Text logs.

From the examples, it looks like there might be ServerVariable values on each Request if you want to try to include in custom logs that are a bit easier to customize than the IIS log itself.

Great Question! and I may have a chance to use this answer m'self.


So ... it looks like you CAN get the ServerVariables from WebAPI but only in an unexpected way. See the snippet below. It seems if you enumerate the collection or call the Keys property all you get is some subset of variables. But if you explicitly request the CRYPT_* variables before any of those actions then you can indeed get them from your controller. I tried this on WebAPI 5.2.6 targeting .net 4.6.2 running under IIS as an Azure Classic Cloud Service. I suggest trying this and seeing if it works for you. If you have a more recent reference for Server Variables, please edit this answer and replace https://learn.microsoft.com/en-us/iis/web-dev-reference/server-variables with your link.

Below worked for me on date of writing for environment listed. It may change in the future. For production I would definitely move this into a helper method.

if (Request.Properties.TryGetValue("MS_HttpContext", out object context))
 {
 if (context is HttpContextWrapper wrapper)
  {
  var v = wrapper.Request?.ServerVariables;
  if (v != null)
   {
   var headers = response.Headers;
   const string CRYPT_PROTOCOL = nameof(CRYPT_PROTOCOL);
   try
    {
    headers.Add($"SV_{CRYPT_PROTOCOL}", $"[{v[CRYPT_PROTOCOL].Replace("\r", "0x0D").Replace("\n", "0x0A")}]");
    }
    catch (Exception ex)
    {
       headers.Add($"SV_{CRYPT_PROTOCOL}", ex.Message);
    }
    foreach (string key in v.AllKeys)
      {
      headers.Add($"SV_{key}", v[key].Replace("\r", "0x0D").Replace("\n", "0x0A"));
      }
     headers.Add($"SV_DONE", "All Server Variables Replaced");
     }
  }
Brettbretz answered 26/11, 2018 at 16:27 Comment(12)
Your answer definitely taught me something I don't know. I have to say that I purposely didn't mention Azure, because I use both Azure and Hosted Servers. And while I TRULY wanted an answer that could give me the information within ASP.NET Web API, having it in an IIS log isn't the worst thing. It just means I wouldn't have Real-Time access to this information during the call; Which may not matter anyway. So I like where this answer is going, and it basically answers the question, but it doesn't help me immediately, which makes me sad. Also, I love your conversational format, lol.Summation
I'm looking into whether or not the ServerVariables mentioned in the article are available in WebAPI. I was able to get to them locally but I doubt IIS Express is doing all the same things IIS is doing. Feel free to try it yourself. I'm just getting a service to log all of the ServerVariable values to see what shows up on a production server for an internet request.Brettbretz
Yes, this is interesting. I will need to test it (mostly, because I want to know whether I have those values - where do those numbers come from?). If @Summation accepts this answer, I will link it when I update mine (TLS1.3 is now up and FW 4.7.2 made some changes to the SSL protocols management, in the HttpClient class for now).Unrounded
I'm going to test it over the next few days as I update some of my MicroServices. My current client I'm doing this for uses Azure AppServices, so that may affect things. If either @Unrounded or myself say it works in either of our environments, I'll mark this as the answer. Either way, definitely an up-vote for an awesome discovery.Summation
@Unrounded if you follow this link and look at the specific CRYPT_* server variables descriptions there are links to the IIS Enums and values. learn.microsoft.com/en-us/iis/web-dev-reference/…Brettbretz
Yes, thanks, I had already found out. It's the same Security Package you can retrieve using the famous QueryContextAttributes of SChannel, through Secure32.dll. I wrote about that function and it's usage in the answer I linked. Very .Net-unfriendly.Unrounded
Any downvoters care to comment publicly? I'd love to correct this answer after all the time I spent yesterday verifying, testing, arguing with IIS PMs, etc.Brettbretz
Yep, subscribed. It would be useful to know what a downvote would imply, here.Unrounded
Consider Upvoting the github "backlog" for documenting this useful security feature. github.com/MicrosoftDocs/iis-docs/issues/212Brettbretz
I executed through the code and did not notice any \n or \r characters. Also, how about just replacing them with empty so that a value to compare becomes available?Coryphaeus
I'm not sure what scenarios result in the whitespace characters and there hasn't seemed to be any harm in having them present. If you want to use this code I suggest putting in your production service for a couple of weeks and log how many times they occur. That will help inform your decision in your environment.Brettbretz
CRYPT_PROTOCOL seems to be 1000 for TLS 1.3.Jeopardize

© 2022 - 2024 — McMap. All rights reserved.