Scenari non compatibili con l'inserimento delle dipendenze per la protezione dati in ASP.NET Core

Di Rick Anderson

Il sistema di protezione dei dati core ASP.NET viene in genere aggiunto a un contenitore del servizio e utilizzato dai componenti dipendenti tramite inserimento delle dipendenze( DI). Tuttavia, esistono casi in cui questo non è fattibile o desiderato, soprattutto quando si importa il sistema in un'app esistente.

Per supportare questi scenari, il pacchetto Microsoft.AspNetCore.DataProtection.Extensions offre un tipo concreto, DataProtectionProvider, che offre un modo semplice per usare la protezione dei dati senza basarsi sull'inserimento delle dipendenze. Il DataProtectionProvider tipo implementa IDataProtectionProvider. La DataProtectionProvider costruzione richiede solo la fornitura di un'istanza DirectoryInfo per indicare dove archiviare le chiavi crittografiche del provider, come illustrato nell'esempio di codice seguente:

using System;
using System.IO;
using Microsoft.AspNetCore.DataProtection;

public class Program
{
    public static void Main(string[] args)
    {
        // Get the path to %LOCALAPPDATA%\myapp-keys
        var destFolder = Path.Combine(
            System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
            "myapp-keys");

        // Instantiate the data protection system at this folder
        var dataProtectionProvider = DataProtectionProvider.Create(
            new DirectoryInfo(destFolder));

        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        Console.Write("Enter input: ");
        var input = Console.ReadLine();

        // Protect the payload
        var protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");

        // Unprotect the payload
        var unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

        Console.WriteLine();
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Enter input: Hello world!
 * Protect returned: CfDJ8FWbAn6...ch3hAPm1NJA
 * Unprotect returned: Hello world!
 *
 * Press any key...
*/

Per impostazione predefinita, il DataProtectionProvider tipo concreto non crittografa il materiale non elaborato prima di renderlo persistente nel file system. Si tratta di supportare scenari in cui lo sviluppatore punta a una condivisione di rete e il sistema di protezione dei dati non può dedurre automaticamente un meccanismo di crittografia della chiave inattivo appropriato.

Inoltre, il DataProtectionProvider tipo concreto non isola le app per impostazione predefinita. Tutte le app che usano la stessa directory chiave possono condividere payload purché corrispondano ai relativi parametri di scopo.

Il DataProtectionProvider costruttore accetta un callback di configurazione facoltativo che può essere usato per modificare i comportamenti del sistema. L'esempio seguente illustra il ripristino dell'isolamento con una chiamata esplicita a SetApplicationName. L'esempio illustra anche la configurazione del sistema per crittografare automaticamente le chiavi persistenti usando Windows DPAPI. Se la directory punta a una condivisione UNC, è possibile distribuire un certificato condiviso in tutti i computer pertinenti e configurare il sistema per l'uso della crittografia basata su certificati con una chiamata a ProtectKeysWithCertificate.

using System;
using System.IO;
using Microsoft.AspNetCore.DataProtection;

public class Program
{
    public static void Main(string[] args)
    {
        // Get the path to %LOCALAPPDATA%\myapp-keys
        var destFolder = Path.Combine(
            System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
            "myapp-keys");

        // Instantiate the data protection system at this folder
        var dataProtectionProvider = DataProtectionProvider.Create(
            new DirectoryInfo(destFolder),
            configuration =>
            {
                configuration.SetApplicationName("my app name");
                configuration.ProtectKeysWithDpapi();
            });

        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        Console.Write("Enter input: ");
        var input = Console.ReadLine();

        // Protect the payload
        var protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");

        // Unprotect the payload
        var unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

        Console.WriteLine();
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }
}

Suggerimento

Le istanze del DataProtectionProvider tipo concreto sono costose da creare. Se un'app gestisce più istanze di questo tipo e se usano tutte la stessa directory di archiviazione delle chiavi, le prestazioni dell'app potrebbero peggiorare. Se si usa il DataProtectionProvider tipo, è consigliabile creare questo tipo una volta e riutilizzarlo il più possibile. Il DataProtectionProvider tipo e tutte le IDataProtector istanze create da esso sono thread-safe per più chiamanti.