3

In this link : https://learn.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.

arman
  • 31
  • 4

1 Answers1

0

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);
    }
SilentTremor
  • 4,747
  • 2
  • 21
  • 34
  • Thank you for the answer but my question is not about how to store the keys, I'm planning to store the data protection keys in the DB or File, and I can use the default Key storage providers for my use. the problem is that when I configure the data protection in the startup to store Keys in DB or File and run the project, there will be a warning in my loges saying: `No XML encryptor configured. Key {b56dffc61e80} may be persisted to storage in unencrypted form.`. so I need to know if I need to encrypt the keys and if I need to, is the solution that I have found valid to use in production. – arman Jan 06 '21 at 13:53
  • I see, well what today is a warning tomorrow will be a error, so yes you should find a way to do it. – SilentTremor Jan 06 '21 at 13:59
  • give a try to this encryption: services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(new DirectoryInfo(@"PATH-HERE")) .UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration() { EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC, ValidationAlgorithm = ValidationAlgorithm.HMACSHA256 }); – SilentTremor Jan 06 '21 at 14:00
  • Yep, still getting the same warning. – arman Jan 06 '21 at 14:08