How to distribute Data Protection keys with an ASP.NET Core web app

Tiago Araújo
The Startup
Published in
5 min readJun 17, 2020

… with Redis.

Photo by Shane Avery on Unsplash

When you configure the Data Protection in your ASP.NET Core web app, by default, it initializes with standard configurations, generally appropriate to a single machine and a single instance web app.

Web applications often need to store security-sensitive data.

The ASP.NET Core data protection stack is designed to serve as the long-term replacement for the <machineKey> element in ASP.NET 1.x — 4.x.

If you see yourself in one of the following scenarios, this “How To” is for you:

  • Your app is spread across multiple machines
  • You have multiple apps in the same machine with shared data
  • For compliance reasons

Many web apps already use Redis as a cache service that can be shared across several servers. Here, I want to show you how to distribute Data Protection keys using the same service - the Redis.

AddDataProtection

The extension method AddDataProtection, for an IServiceCollection interface returns an IDataProtectionBuilder that “exposes” other extension methods to customize the best scenario for your application.

Extension methods to IDataProtectionBuilder.

Keep in mind that when you are configuring the services of your application (Authentication, Session, Anti-Forgery) some of them try to add the data protection layer. So, it’s good practice to register the DataProtection before it happens.

SetApplicationName

The application descriptor in the data protection system enables the isolation of applications. By default, the name is the content root path, but for some scenarios listed above the path can be different for different environments. So it is important to always set the application name when you want to share protected payloads among apps.

Unique name of this application within the data protection system.

Configure SetApplicationName in each app with the same value.

PersistKeysTo* and ProtectKeysWith*

Before you configure the key storage it is important to explain what PersistKeysTo* and ProtectKeysWith* configurations are. If you already know about it skip to the next chapter.

PersistKeysTo*

The extension methods that start by PersistKeysTo* for the IDataProtectionBuilder interface, configures the key storage that will store the valid and outdated keys. To share the keys among apps the key storage should be accessible to every app. e.g. Redis Server, Database Server, Azure Blob, or even a file system. You can see here some key storages available on ASP.NET Core distribution. By default, keys are generated with a 90 days validation period since the activation date. Below you can see an example of a key format stored on a key storage.

Generated key sample for ASP.NET Core

After the expiration date, you must store the outdated key to unprotect data that was previously protected by that key. In my experience, the rollout of new keys and the use of outdated ones works very well and ASP.NET Core optimizes the caching process of the keys in memory. See more details here.

ProtectKeysWith*

The keys of your key storage can be protected using a X.509 certificate. It can make sense for the following scenarios:

  • The repository may be accessible for many users/applications
  • For compliance reasons

ProtectKeys can be configurated using an installed certificate on your machine, or a service that manages your certificates, such as AzureVault or Windows DPAPI.

IMPORTANT: Your certificates are secure and I am assuming that no one has access to them.

PersistKeysToRedis

The Microsoft.AspNetCore.DataProtection.StackExchangeRedis package allows you to store data protection keys in a Redis cache backed by a list entry. This list entry will be stored on the redis key received on the second parameter, e.g. “DataProtection-Keys” as you can see below.

Configuration of Redis as key storage of the Data Protection

In the Step-by-Step Configuration section, you can see how to configure the XML repository manually, by getting the redis URI and the redis key from the application configurations.

IMPORTANT: Redis is a non-persistent database by default, please ensure that Redis is configured as persistent.

Customize KeyManagementOptions

If you use the configurations using the Microsoft.Extensions.Configuration with the dependency injection then you can load those configurations and bind the KeyManagementOptions automatically.

Bellow, you can see two ways to load the options. You can do it by using constants (magic string and number) or by loading the configurations from a configuration section.

Configuration of KeyManagementOptions from the application configurations

Step-by-Step Configuration

  1. Add the Data Protection dependencies;
  2. Set application name;
  3. Configure the key storage (Redis or FileSystem, AzureBlob, EntityFramework, etc);
  4. Personalize the KeyManagementOptions;
  5. (Optional) Protect your keys with a certificate X509.

OK, and that’s it! You can check below an example of the entire process and if you want you can see more samples here.

… and as always feel free to contact me if you have any questions.

Conclusion

Data Protection offers a simple consumer-facing API and a simplicity of configurations with almost zero-configuration needed. As we explored, in some cases it is necessary to configure a specific aspect of Redis as key storage. However, it is possible to go deeper and configure data protection with infinite possibilities.

Pros: Using Redis as key storage is the best way to share keys for multiple applications because some web apps already use it to share authentication cookies or CSRF protection across multiple servers.

Cons: If you lose the redis key or the entire database with the master keys of Data Protection, your applications won’t be able to unprotect data previously protected with those keys.

References

--

--

Tiago Araújo
The Startup

SOFTWARE ENGINEER to make money — Listen to MUSIC for energy — RIDE for no reason to the heart — SHARE with loved ones — The DREAM: the last 3 in the same box