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?
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");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With