Forcing an old .NET application to support TLS 1.2 without recompiling it

As most servers are moving toward TLS 1.3 and removing TLS 1.0/1.1 support, examples of legacy .NET applications – compiled with an old version of the .NET Framework, like 4.0 or 4.5 – experiencing connectivity issues with TLS 1.2 servers are becoming more and more common, specially since installing a more recent version of the .NET Framework is not sufficient: it's the version used for compiling your project that actually matters when it comes to selecting the supported TLS versions during the TLS handshake.

To make migration a bit less painful, Microsoft published a "transport security best practices" paper that list a few solutions that help avoid handshake errors related to the use of legacy TLS versions that are no longer considered safe.

One of the proposed solutions is to update your project to target .NET Framework 4.7: in this case, you'll have nothing else to do, as .NET 4.7 applications automatically default to whatever the operating system they run on offers and considers safe (which currently includes TLS 1.2 and will later include TLS 1.3).

Unfortunately, such an option requires re-compiling the application, which is not always feasible. Thankfully, you can also force an existing application to use the system default TLS versions without having to re-compile it (assuming it doesn't explicitly set the SSL/TLS versions it prefers via ServicePointManager).

The best practices paper lists a few options, but my favourite one is the one that consists in simply updating the configuration file associated with the application executable, as it's easy to do and doesn't impact anything else on the machine.

For that, locate the configuration file associated to the executable of the application you want to add TLS 1.2 support to: it's always named [name of the executable].exe.config. If there's no such file, create one. Once located or created, update its content to enable the compatibility switch required to support TLS 1.2:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=false"/>
</runtime>
</configuration>

If you're still using Windows 7, you'll also have to tweak the registry to enable TLS 1.2 support, as indicated on https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings.

OpenIddict 1.0 and 2.0 general availability

I'm very happy to announce that OpenIddict 1.0 and 2.0 final packages were pushed earlier today to NuGet.org and are now officially available!

What changed new since RC3?

A security bug was fixed

A few days ago, a vulnerability impacting application permissions was publicly reported by nurhat on GitHub (many thanks to him!).

In a nutshell, scope permissions were not correctly enforced for public clients using the password flow and custom grant types (confidential clients or clients using the code or client credentials flows were not impacted).

A fix was immediately added to the nightly builds and is present in the RTM release.

Built-in entity caches are now included

OpenIddict now comes with built-in entity caching to avoid having to send multiple requests to retrieve the same entities. Concretely, if your AuthorizationController uses APIs like OpenIddictApplicationManager.FindByClientIdAsync(request.ClientId), the corresponding application will be directly retrieved from the cache and the resulting operation will be extremely cheap.

To ensure this feature works with non-thread-safe stores and stores that rely on context-affinity (like Entity Framework 6.x or Entity Framework Core), these built-in caches are scoped so that cached entities are not reused across requests.

While definitely not recommended, this feature can be disabled via the OpenIddict core options:

1
2
3
4
5
6
7
services.AddOpenIddict()
.AddCore(options =>
{
// ...

options.DisableEntityCaching();
})

Read more

Highway to (DLL) Hell

It's no secret that I've always been a huge fan of Windows Media Center, probably the best digital/personal video recorder out there and definitely one of the most impressive Microsoft applications developed using the .NET Framework.

As an avid WMC user, I have built 3 HTPC machines and recorded thousands of TV programs (movies, series, documentaries, etc.). As such, when Microsoft announced in May 2015 that Windows Media Center would no longer be developed (almost 6 year after disbanding the development team!) – and thus would not be part of Windows 10 – I refused to migrate to Windows 10, despite Microsoft's offers encouraging users to upgrade their OS for free.

The fact Windows Media Center was not available on Windows 10 – even as a paid feature like it was on Windows 8.x – was a major blocker for many users. To work around this limitation, enthusiasts decided to create an unofficial port of Windows Media Center for Windows 10.

While unofficial, the port worked just fine. But over time, Microsoft started to update some of the system components Windows Media Center relied on, causing annoying bugs. For instance, the introduction of breaking changes in Windows 10 1803 made watching a .wtv file (WMC's TV file format) recorded on Windows 7 completely impossible.

While investigating, I discovered that the issue was caused by a change in MSVidCtl.dll, the system-wide DLL containing the DirectShow components needed by WMC for all its TV-related features. After replacing the faulty DLL by an older version, WMC was able to play old recordings like a charm.

This phenomenom, that occurs every time API or functional changes are introduced in a DLL a program depends on, has a name: DLL Hell.

Read more

Session fixation vulnerability in the Auth0 ASP.NET and OWIN SDKs

Recently, I received a mail from Auth0 asking me if I was interested in joining them. I had used Auth0 many times in the past but I had never taken the time to look at their OSS SDKs. This mail was a good opportunity to change that.

When doing so, I discovered that both their ASP.NET 4.x and OWIN/Katana SDKs were unfortunately prone to "session fixation", which is a form of cross-site request forgery allowing to force a victim to log in under an attacker's account.

Since it's a quite frequent vulnerability, here's a quick overview of what causes it and how you can concretly exploit it.

Auth0 was already aware of this issue internally and decided to switch to the official OWIN OpenID Connect middleware developed by Microsoft, which is not prone to this class of attack.

If you need to migrate, Auth0 has prepared a migration guide listing the steps required to replace Auth0-ASPNET-Owin by Microsoft's OpenID Connect middleware.

What do session fixation attacks consist in?

The OAuth 2.0 threat model RFC – a must read for anyone dealing with OAuth 2.0 and OpenID Connect – gives an excellent definition of this threat and its practical implications:

Cross-site request forgery (CSRF) is a web-based attack whereby HTTP requests are transmitted from a user that the web site trusts or has authenticated (e.g., via HTTP redirects or HTML forms). CSRF attacks on OAuth approvals can allow an attacker to obtain authorization to OAuth protected resources without the consent of the user. This attack works against the redirect URI used in the authorization "code" flow.

An attacker could authorize an authorization "code" to their own protected resources on an authorization server. He then aborts the redirect flow back to the client on his device and tricks the victim into executing the redirect back to the client. The client receives the redirect, fetches the token(s) from the authorization server, and associates the victim's client session with the resources accessible using the token.

Impact: the user accesses resources on behalf of the attacker. The effective impact depends on the type of resource accessed. For example, the user may upload private items to an attacker's resources. Or, when using OAuth in 3rd-party login scenarios, the user may associate his client account with the attacker's identity at the external Identity Provider. In this way, the attacker could easily access the victim's data at the client by logging in from another device with his credentials at the external Identity Provider.

Usually, this (generally underestimated) threat is mitigated by correlating the authorization response with the authorization request: typically, by generating an unguessable value before redirecting the user to the Identity Provider and validating it before sending the token request.

Unfortunately, this kind of check is not made by the Auth0 ASP.NET 4.x and OWIN SDKs, making them vulnerable to this class of attack.

Read more

Implementing advanced scenarios using the new OpenIddict RC3 events model

Prior to OpenIddict RC3, the events model used by the OpenID Connect server middleware (i.e the OIDC server framework behind OpenIddict) was deliberately not accessible due to the nature of OpenIddict: being initially designed for non-experts, exposing such a powerful API – that allows altering the way OpenID Connect requests are processed – didn't seem like a good idea at first sight.

With time, the core audience of OpenIddict has evolved a bit to not only include beginners but also developers who were already familiar with OAuth/OpenID Connect or had used OAuthAuthorizationServerMiddleware or ASOS in the past. For them, the fact OpenIddict didn't allow them to take control of the request processing pipeline was often a blocker. With the introduction of OpenIddict RC3, we're changing that.

Using these advanced APIs is not recommended if you're not familiar with the OAuth/OpenID Connect specifications or with the events model used by the OpenID Connect server middleware. If you're not sure whether you should use these APIs, don't hesitate to reach us on Gitter or on GitHub.

Introducing event handlers

The events model is structured around IOpenIddictServerEventHandler<TEvent> and IOpenIddictValidationEventHandler<TEvent>. These 2 interfaces represent handlers that are invoked every time an event of type TEvent is triggered by the OpenIddict server or validation handlers.

At the time of writing, OpenIddict exposes 44 server events – grouped into the OpenIddictServerEvents static class to make them easier to find – and 5 validation events, exposed under OpenIddictValidationEvents.

Each event represents a specific moment in the request processing pipeline (e.g the moment the OpenIddict server determines whether the request is an OpenID Connect request it should handle, the moment it extracts it, handles it or returns a response).

Multiple handlers of the same type can be registered: they will be sequentially invoked in the same order as the one used to register them. As soon as a handler calls a method that indicates the request should no longer be processed (e.g HandleResponse() or SkipHandler()), OpenIddict will stop invoking the handlers and the next ones will be automatically ignored.

For security reasons, the custom handlers will be invoked by OpenIddict after its own validation routines. If a request is rejected by OpenIddict, your own handlers won't be invoked.

Creating and registering a custom event handler

Creating an event handler is straightforward: pick the event you need and add a class that implements either IOpenIddictServerEventHandler<TEvent> (for a handler that receives events triggered by the OpenIddict server services) or IOpenIddictValidationEventHandler<TEvent> (for a handler that receives events triggered by the OpenIddict token validation services):

For instance, to return custom metadata in the discovery document, you'll need to implement IOpenIddictServerEventHandler<OpenIddictServerEvents.HandleConfigurationRequest>:

1
2
3
4
5
6
7
8
9
public class MyEventHandler : IOpenIddictServerEventHandler<OpenIddictServerEvents.HandleConfigurationRequest>
{
public Task HandleAsync(OpenIddictServerEvents.HandleConfigurationRequest notification, CancellationToken cancellationToken)
{
notification.Context.Metadata["company_name"] = "Contoso";

return Task.CompletedTask;
}
}

To register it, use options.AddEventHandler<TEvent, THandler>() (by default, the handler is registered as a scoped service):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void ConfigureServices(IServiceCollection services)
{
services.AddOpenIddict()

// Register the OpenIddict core services.
.AddCore(options =>
{
// ...
})

// Register the OpenIddict server handler.
.AddServer(options =>
{
// ...

options.AddEventHandler<OpenIddictServerEvents.HandleConfigurationRequest, MyEventHandler>();
})

// Register the OpenIddict validation handler.
.AddValidation();
}

Read more