[SOLVED] Using an in-memory repository. Keys will not be persisted to storage. - ASP.NET Core under IIS

easily-display-java
POST
mmombrea-headshot
By Matt Mombrea
Share

.NET Core Data Protection

One of the main benefits of building a new .NET project using .NET Core is cross platform deployment, however, IIS will still be a common home for ASP.NET Core web applications.

In netcore 2.0 MVC applications, a transparent feature that is configured during app Startup is Data Protection. Data Protection provides a cryptographic foundation for things like ASP.NET Identity among many others.

When the Data Protection system is initialized, it applies default settings based on the operational environment. These settings are generally appropriate for apps running on a single machine.  - Rick Anderson

The app attempts to detect its operational environment and handle key configuration on its own. (cite)

Default Configuration Logic

  • 1) If the app is hosted in Azure Apps, keys are persisted to the %HOME%\ASP.NET\DataProtection-Keys folder. This folder is backed by network storage and is synchronized across all machines hosting the app.
    • Keys aren't protected at rest.
    • The DataProtection-Keys folder supplies the key ring to all instances of an app in a single deployment slot.
    • Separate deployment slots, such as Staging and Production, don't share a key ring. When you swap between deployment slots, for example swapping Staging to Production or using A/B testing, any app using Data Protection won't be able to decrypt stored data using the key ring inside the previous slot. This leads to users being logged out of an app that uses the standard ASP.NET Core cookie authentication, as it uses Data Protection to protect its cookies. If you desire slot-independent key rings, use an external key ring provider, such as Azure Blob Storage, Azure Key Vault, a SQL store, or Redis cache.
  • 2) If the user profile is available, keys are persisted to the %LOCALAPPDATA%\ASP.NET\DataProtection-Keys folder. If the operating system is Windows, the keys are encrypted at rest using DPAPI.
  • 3) If the app is hosted in IIS, keys are persisted to the HKLM registry in a special registry key that is ACLed only to the worker process account. Keys are encrypted at rest using DPAPI.
  • 4) If none of these conditions match, keys aren't persisted outside of the current process. When the process shuts down, all generated keys are lost.

For IIS, the item we're interested in here is #3. The default configuration will store the keys in the system registry, that way the keys persist between AppPool restarts and machine restarts. It also lets you share the same key between applications if necessary (via a configuration addition to Startup.cs).

The Problem

Once you deploy your app and run it under an IIS App Pool, you may find that the Data Protection keys are not being persisted. If you have error logging you'll see entries like this:

  • No XML encryptor configured. Key may be persisted to storage in unencrypted form.
  • Neither user profile nor HKLM registry available. Using an ephemeral key repository. Protected data will be unavailable when application exits.
  • Using an in-memory repository. Keys will not be persisted to storage.

This means that each time your app pool restarts, new keys will be generated and any encrypted codes or values which have been stored or transmitted will no longer be usable. A basic example of this is a Forgotten Password request using ASP.NET Core Identity. If you request a password reset email, an encrypted URL will be sent in the email for you to click on. If the app pool restarts before you get around to clicking that link, the token will not be able to be decrypted and the reset will fail. This scenario becomes much worse if you're storing long term encrypted data for later decryption.

So what is happening? Why is the default storage method of the system registry failing?

The Solution

This issue stems from a bug in IIS itself which may or may not ever be corrected. In order to work around the issue, it's necessary for you to edit your App Pool to enable User Profile Loading. Once you set your App Pool to load the user profile for the application pool identity, the application will have permission to read and write to the system registry as intended.

Alternatively, you can configure Data Protection to use a different method of key storage, like a UNC share.

 

 

 

POST
mmombrea-headshot
By Matt Mombrea
Share

2 Comments

  1. Author's Headshot
    Alan January 22, 2020
    Reply

    Thanks no much. Your fix worked perfectly.

  2. Author's Headshot
    Great May 14, 2020
    Reply

    Thanks so much for the explanation...I was thinking it is a bug in my code.As for me,i encrypt and save keys for decrypting to database or encrypt them in a text file.I will work around your fix cause i hate seeing those warning in my logs folder

Leave a Reply

Your email address will not be published. Required fields are marked *

Meet the Author

mmombrea-headshot
CTO / Partner

Matthew Mombrea

Matt is our Chief Technology Officer and one of the founders of our agency. He started Cypress North in 2010 with Greg Finn, and now leads our Buffalo office. As the head of our development team, Matt oversees all of our technical strategy and software and systems design efforts.

With more than 19 years of software engineering experience, Matt has the knowledge and expertise to help our clients find solutions that will solve their problems and help them reach their goals. He is dedicated to doing things the right way and finding the right custom solution for each client, all while accounting for long-term maintainability and technical debt.

Matt is a Buffalo native and graduated from St. Bonaventure University, where he studied computer science.

When he’s not at work, Matt enjoys spending time with his kids and his dog. He also likes to golf, snowboard, and roast coffee.