App-vNext / Polly

Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner. From version 6.0.1, Polly targets .NET Standard 1.1 and 2.0+.
https://www.thepollyproject.org
BSD 3-Clause "New" or "Revised" License
13.44k stars 1.23k forks source link

Securing data in Polly cache #635

Closed phatcher closed 5 years ago

phatcher commented 5 years ago

Summary: What are you wanting to achieve? When data is stored in a cache, you can retrieve it if you have access and an appropriate key, but depending on the nature of the data it might be important to encrypt it in some manner.

ASP.NET Core introduces interfaces to help with this IDataProtectionProvider/IDataProtector. This allows you to encrypt/decrypt the data stored in the cache in a secure manner for the app/purpose.

Here's an example usage where access tokens are cached encrypted

What code or approach do you have so far?
Here's a rough mock up of what I think it should be...

IDataProtectionProvider provider = services.GetRequiredService<IDataProtectionProvider>();
var dataProtector = provider.CreateProvider("Foo")
var cachePolicy = Policy.Cache<byte[]>(distributedCache.AsSyncCacheProvider<byte[]>(), dataProtector, TimeSpan.FromMinutes(5));

Alternatively we could inject the provider and purpose

IDataProtectionProvider provider = services.GetRequiredService<IDataProtectionProvider>();
var cachePolicy = Policy.Cache<byte[]>(distributedCache.AsSyncCacheProvider<byte[]>(), provider, "Foo", TimeSpan.FromMinutes(5));

Thoughts/comments?

phatcher commented 5 years ago

Oh, the method could be SecureCache to differentiate it and avoid more overloads of the same method

reisenberger commented 5 years ago

@phatcher . I am thinking that this could be achieved with no changes to existing Polly. Encryption and decryption is just a form of data manipulation on the way in and out of cache, similar to serialization. An implementation of ICacheItemSerializer<TUnecnrpyted, TEncrypted> could be made, which is configured with and delegates to an IDataProtector. Something like:

DataProtectionSerializer : ICacheItemSerializer<TUnecnrypted, TEncrypted>
{
    private IDataProtector _protector;

    public DataProtectionSerializer(IDataProtector protector) => _protector = protector; /* add null defence */

    TEncrypted Serialize(TUnecnrypted objectToSerialize) => protector.Protect(objectToSerialize);
    TUnecnrypted Deserialize(TEncrypted objectToDeserialize) => protector.Unprotect(objectToDeserialize);
}

I haven't tested this - it's a sketch for you potentially to build on, to get you a quicker reply. Do you think something like this works?

EDIT: The page linked to describes how to use such an ICacheItemSerializer<TUnecnrypted, TEncrypted> with the policy.

phatcher commented 5 years ago

@reisenberger Yes, something like that, the encryption is just a decorator around the cache serialization. How you get to the correct IDataProtectionProvider is a setup issue anyway, so its fine.

I'm not sure how long an IDataProtector is supposed to live for, so I might change it to something like this..

DataProtectionSerializer : ICacheItemSerializer<TUnecnrypted, TEncrypted>
{
    private IDataProtectonProvicer _provider;
    private string _purpose;

    public DataProtectionSerializer(IDataProtectionProvider protector, string purpose)
    {
      _provider = provider; /* add null defence */
      _purpose = purpose; /* add null defence */
    }

    TEncrypted Serialize(TUnecnrypted objectToSerialize) => Protector.Protect(objectToSerialize);
    TUnecnrypted Deserialize(TEncrypted objectToDeserialize) => Protector.Unprotect(objectToDeserialize);

    private IDataProtector Prototector => _provider.CreateProtector(_purpose);
}

I'll have a play and if it works nicely, I'll update the documentation pages - might take me a few days

reisenberger commented 5 years ago

@phatcher How did this work out? Anything more we should add, before closing this?

I updated the Polly wiki to highlight the possibility of using ICacheItemSerializer` for data encryption.

phatcher commented 5 years ago

Didn't make it to the top of my development queue yet, I think the doc update is good enough for now as I have an internal tracking issue

reisenberger commented 5 years ago

Np.