Share via


Scénarios non compatibles avec l’injection de dépendances pour la protection des données dans ASP.NET Core

Par Rick Anderson

Le système de protection des données ASP.NET Core est normalement ajouté à un conteneur de service et consommé par les composants dépendants via l’injection de dépendances (DI). Toutefois, il existe des cas où cela n’est pas possible ou souhaité, en particulier lors de l’importation du système dans une application existante.

Pour prendre en charge ces scénarios, le package Microsoft.AspNetCore.DataProtection.Extensions fournit un type concret, DataProtectionProvider, qui offre un moyen simple d’utiliser la protection des données sans recourir à la DI. Le type DataProtectionProvider implémente IDataProtectionProvider. La construction de DataProtectionProvider nécessite uniquement la fourniture d’une instance DirectoryInfo pour indiquer où les clés de chiffrement du fournisseur doivent être stockées, comme indiqué dans l’exemple de code suivant :

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...
*/

Par défaut, le type concret DataProtectionProvider ne chiffre pas la matière de clé brute avant de la rendre persistante dans le système de fichiers. Il s’agit de prendre en charge les scénarios dans lesquels le développeur pointe vers un partage réseau et où le système de protection des données ne peut pas déduire automatiquement un mécanisme de chiffrement de clé au repos approprié.

En outre, le type concret DataProtectionProvidern’isole pas les applications par défaut. Toutes les applications utilisant le même répertoire de clés peuvent partager des charges utiles tant que leurs paramètres d’objectif correspondent.

Le constructeur DataProtectionProvider accepte un rappel de configuration facultatif qui peut être utilisé pour ajuster les comportements du système. L’échantillon ci-dessous illustre la restauration de l’isolation avec un appel explicite à SetApplicationName. L’échantillon montre également la configuration du système pour chiffrer automatiquement les clés persistantes à l’aide de Windows DPAPI. Si le répertoire pointe vers un partage UNC, vous pouvez distribuer un certificat partagé sur toutes les machines pertinentes et configurer le système pour utiliser le chiffrement basé sur les certificats avec un appel à 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();
    }
}

Conseil

Les instances du type concret DataProtectionProvider sont coûteuses à créer. Si une application gère plusieurs instances de ce type et qu’elles utilisent toutes le même répertoire de stockage de clés, les performances de l’application peuvent se dégrader. Si vous utilisez le type DataProtectionProvider, nous vous recommandons de créer ce type une seule fois et de le réutiliser autant que possible. Le type DataProtectionProvider et toutes les instances IDataProtector créées à partir de celui-ci sont thread-safe pour plusieurs appelants.