asp.net core data protection key encrypt

Viewed 1613

In this link : https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-5.0#data-protection

it says "If data protection isn't configured, the keys are held in memory and discarded when the app restarts.", and I don't want that to happen so I configured the data protection in a startup.cs :

 services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"PATH-HERE"))

and when I started the app to test it, a warning shows up in the logs saying: No XML encryptor configured. Key {GUID} may be persisted to storage in unencrypted form..

I have found out that I need to use ProtectKeysWith* to encrypt the Key. but because I'm trying to publish the app to a Linux server, I cant use ProtectKeysWithDpapi or ProtectKeysWithDpapiNG ( because they can only be used on Windows servers ), so the only option left was X.509.

basically, I did some searching, and I found out I can use these commands to create a self-signed X.509 certificate :

"C:\Program Files\Git\usr\bin\openssl.exe" genrsa -out private.key 2048

"C:\Program Files\Git\usr\bin\openssl.exe" req -new -x509 -key private.key -out publickey.cer -days 2000

"C:\Program Files\Git\usr\bin\openssl.exe" pkcs12 -export -out idp.pfx -inkey private.key -in publickey.cer

and I can add this certificate in the startup like this :

services
   .AddDataProtection()
   .PersistKeysToFileSystem(new DirectoryInfo(@"PATH-TO-SAVE-KEYS"))
   .SetDefaultKeyLifetime(new TimeSpan(90, 0, 0, 0, 0))
   .SetApplicationName("APPNAME-HERE")
   .ProtectKeysWithCertificate(new X509Certificate2(@"CERTIFICATE-PATH", "CERTIFICATE-PASSWORD"));

So my question is do I even need to encrypt the keys? and if I should, is my solution valid? can I use this solution in production without any problem? ( keep in mind that I'm going to use a Linux server for my app )

Update 1: I did more digging in the StackOverflow questions and I have found this : https://stackoverflow.com/a/48867984/14951696.

apparently using a self-signed certificate ( like what I was doing ) will be fine as long as you are using it internally. I will update again after I have published my app in case anyone has the same question.

Update 2: I have decided to use Windows servers, and I have found no problem using the self-signed certificate to encrypt the keys. if anything happens I will update again.

1 Answers

My two cents on this, don't know what the problem is with what you found, if not you can us bellow solution.

In order to have a shared Data Protection key is needed to explicitly enforce it. With one note, in at startup is key doesn't exist in the source is created with an expiration associated. The Ideea is to save XElement and the name of it on a storage that can be used to retrieve at startup that value.

At startup:

 services.Configure<KeyManagementOptions>(options =>
        {
            IDataProtectionRepo dataProtection = services.BuildServiceProvider().GetRequiredService<IDataProtectionRepo>();
            options.NewKeyLifetime = DateTime.Now.AddYears(10) - DateTime.Now; // new one is created
            options.XmlRepository = new DataProtectionKeyRepository(dataProtection);
        });

where DataProtectionKeyRepository is the implementation of IXmlRepository

public class DataProtectionKeyRepository : IXmlRepository
{
 
    private IDataProtectionRepo dataProtectionRepo;
    public DataProtectionKeyRepository(IDataProtectionRepo dataProtectionRepo)
    {
        this.dataProtectionRepo = dataProtectionRepo;
    }

    public IReadOnlyCollection<XElement> GetAllElements()
    {
        return new ReadOnlyCollection<XElement>(dataProtectionRepo.GetAll().Select(k => XElement.Parse(k.XmlData)).ToList());
    }

    public void StoreElement(XElement element, string friendlyName)
    {
        dataProtectionRepo.AddOrUpdate(new ProtectionKeyModel { Name = friendlyName, XmlData = element.ToString() });
    }
}

Communication class

public class ProtectionKeyModel
    {
        public string Name { get; set; }
        public string XmlData { get; set; }
    }

And the storage repo, can be a DB, file system, cloud storage, whatever is fine for you, implement bellow interface how you like to

public interface IDataProtectionRepo
    {
        IEnumerable<ProtectionKeyModel> GetAll();
        void AddOrUpdate(ProtectionKeyModel protectionKeyModel);
    }
Related