Fournisseurs de stockage de clé dans ASP.NET Core

Le système de protection des données utilise un mécanisme de découverte par défaut pour déterminer où les clés de chiffrement doivent être persistantes. Le développeur peut remplacer le mécanisme de découverte par défaut et spécifier l’emplacement manuellement.

Avertissement

Si vous spécifiez un emplacement de persistance de clés explicite, le système de protection des données désinscrit le mécanisme de chiffrement de clés au repos par défaut, de sorte que les clés ne sont plus chiffrées au repos. Nous recommandons également de spécifier un mécanisme de chiffrement de clés explicite pour des déploiements de production.

Système de fichiers

Pour configurer un référentiel de clés basé sur un système de fichiers, appelez la routine de configuration PersistKeysToFileSystem comme indiqué ci-dessous. Fournissez un DirectoryInfo pointant vers le référentiel où des clés doivent être stockées :

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys\"));
}

Le DirectoryInfo peut pointer vers un répertoire sur l’ordinateur local ou vers un dossier sur un partage réseau. Si vous pointez vers un répertoire sur l’ordinateur local (et que le scénario est que seules les applications sur l’ordinateur local nécessitent un accès pour utiliser ce référentiel), envisagez d’utiliser Windows DPAPI (sur Windows) pour chiffrer les clés au repos. Sinon, envisagez d’utiliser un certificat X.509 pour chiffrer des clés au repos.

Stockage Azure

Le package Azure.Extensions.AspNetCore.DataProtection.Blobs permet de stocker des clés de protection des données dans Stockage Blob Azure. Des clés peuvent être partagées entre plusieurs instances d’une application web. Des applications peuvent partager des authentifications cookie ou une protection CSRF sur plusieurs serveurs.

Pour configurer le fournisseur de Stockage Blob Azure, appelez l’une des surcharges PersistKeysToAzureBlobStorage.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToAzureBlobStorage(new Uri("<blob URI including SAS token>"));
}

Si l’application web s’exécute en tant que service Azure, une chaîne de connexion peut être utilisée pour s’authentifier auprès du stockage Azure en utilisant Azure.Storage.Blobs.

string connectionString = "<connection_string>";
string containerName = "my-key-container";
string blobName = "keys.xml";
BlobContainerClient container = new BlobContainerClient(connectionString, containerName);

// optional - provision the container automatically
await container.CreateIfNotExistsAsync();

BlobClient blobClient = container.GetBlobClient(blobName);

services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(blobClient);

Remarque

La chaîne de connexion à votre compte de stockage se trouve dans le Portail Azure sous la section « Clés d’accès » ou en exécutant la commande CLI suivante :

az storage account show-connection-string --name <account_name> --resource-group <resource_group>

Redis

Le package Microsoft.AspNetCore.DataProtection.StackExchangeRedis permet de stocker des clés de protection des données dans un cache Redis. Des clés peuvent être partagées entre plusieurs instances d’une application web. Des applications peuvent partager des authentifications cookie ou une protection CSRF sur plusieurs serveurs.

Le package Microsoft.AspNetCore.DataProtection.Redis permet de stocker des clés de protection des données dans un cache Redis. Des clés peuvent être partagées entre plusieurs instances d’une application web. Des applications peuvent partager des authentifications cookie ou une protection CSRF sur plusieurs serveurs.

Si vous souhaitez configurer sur Redis, appelez l’une des surcharges PersistKeysToStackExchangeRedis :

public void ConfigureServices(IServiceCollection services)
{
    var redis = ConnectionMultiplexer.Connect("<URI>");
    services.AddDataProtection()
        .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys");
}

Si vous souhaitez configurer sur Redis, appelez l’une des surcharges PersistKeysToRedis :

public void ConfigureServices(IServiceCollection services)
{
    var redis = ConnectionMultiplexer.Connect("<URI>");
    services.AddDataProtection()
        .PersistKeysToRedis(redis, "DataProtection-Keys");
}

Pour plus d’informations, voir les rubriques suivantes :

Registre

S’applique uniquement aux déploiements Windows.

Il est possible que l’application ne puisse parfois pas avoir d’accès en écriture au système de fichiers. Envisagez un scénario où une application s’exécute en tant que compte de service virtuel (par exemple une identité du pool d’applications de w3wp.exe). Dans ce cas, l’administrateur peut approvisionner une clé de Registre accessible par l’identité du compte de service. Appelez la méthode d’extension PersistKeysToRegistry comme illustré ci-dessous. Fournissez un RegistryKey pointant vers l’emplacement où les clés de chiffrement doivent être stockées :

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Sample\keys", true));
}

Important

Nous vous recommandons d’utiliser Windows DPAPI pour chiffrer les clés au repos.

Entity Framework Core

Le package Microsoft.AspNetCore.DataProtection.EntityFrameworkCore fournit un mécanisme de stockage des clés de protection des données dans une base de données en utilisant Entity Framework Core. Le package NuGet Microsoft.AspNetCore.DataProtection.EntityFrameworkCore doit être ajouté au fichier projet. Il ne fait pas partie du métapaquet Microsoft.AspNetCore.App.

Avec ce package, des clés peuvent être partagées entre plusieurs instances d’une application web.

Pour configurer le fournisseur EF Core, appelez la méthode PersistKeysToDbContext :

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    // Add a DbContext to store your Database Keys
    services.AddDbContext<MyKeysContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("MyKeysConnection")));

    // using Microsoft.AspNetCore.DataProtection;
    services.AddDataProtection()
        .PersistKeysToDbContext<MyKeysContext>();

    services.AddDefaultIdentity<IdentityUser>()
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Si vous souhaitez voir les commentaires de code traduits dans une langue autre que l’anglais, dites-le nous dans cette discussion GitHub.

Le paramètre générique, TContext, doit hériter de DbContext et implémenter IDataProtectionKeyContext :

using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using WebApp1.Data;

namespace WebApp1
{
    class MyKeysContext : DbContext, IDataProtectionKeyContext
    {
        // A recommended constructor overload when using EF Core 
        // with dependency injection.
        public MyKeysContext(DbContextOptions<MyKeysContext> options) 
            : base(options) { }

        // This maps to the table that stores keys.
        public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
    }
}

Créez la table DataProtectionKeys.

Exécutez les commandes suivantes dans la fenêtre de la console du Gestionnaire de package :

Add-Migration AddDataProtectionKeys -Context MyKeysContext
Update-Database -Context MyKeysContext

MyKeysContext est le DbContext défini dans l’exemple de code précédent. Si vous utilisez un DbContext avec un autre nom, remplacez votre nom DbContextpar MyKeysContext.

La classe/l’entité DataProtectionKeys adopte la structure illustrée dans la table suivant.

Propriété/Champ Type CLR Type SQL
Id int int, PK, IDENTITY(1,1), non nul
FriendlyName string nvarchar(MAX), nul
Xml string nvarchar(MAX), nul

Référentiel de clés personnalisé

Si les mécanismes fournis ne sont pas appropriés, le développeur peut spécifier son propre mécanisme de persistance de clés en fournissant un IXmlRepository personnalisé.