Configurer la protection des données ASP.NET Core
Lorsque le système de protection des données est initialisé, il applique les paramètres par défaut en fonction de l’environnement opérationnel. Ces paramètres sont appropriés pour les applications s’exécutant sur un seul ordinateur. Toutefois, il existe des cas où un développeur peut vouloir modifier les paramètres par défaut :
- L’application est répartie sur plusieurs ordinateurs.
- Pour des raisons de conformité.
Pour ces scénarios, le système de protection des données offre une API de configuration riche.
Avertissement
Comme pour les fichiers de configuration, l’anneau de clés de protection des données doit être protégé à l’aide des autorisations appropriées. Vous pouvez choisir de chiffrer les clés au rest, mais cela n’empêche pas les cyberattaquants de créer de nouvelles clés. Par conséquent, la sécurité de votre application est affectée. L’emplacement de stockage configuré avec Data Protection doit avoir son accès limité à l’application elle-même, comme vous le feriez pour protéger les fichiers de configuration. Par exemple, si vous choisissez de stocker votre anneau de clés sur le disque, utilisez les autorisations du système de fichiers. Vérifiez que seule l’identity sous laquelle votre application web s’exécute dispose d’un accès en lecture, écriture et création à ce répertoire. Si vous utilisez Stockage Blob Azure, seule l’application web doit avoir la possibilité de lire, d’écrire ou de créer de nouvelles entrées dans le magasin d’objets blob, etc.
La méthode d’extension AddDataProtection retourne un IDataProtectionBuilder. IDataProtectionBuilder
expose les méthodes d’extension que vous pouvez chaîner ensemble pour configurer les options de protection des données.
Remarque
Cet article a été écrit pour une application qui fonctionne dans un conteneur Docker. Dans un conteneur Docker, l’application a toujours le même chemin et, par conséquent, le même discriminateur d’application. Les applications qui doivent être exécutées dans plusieurs environnements (par exemple, local et déployé) doivent définir le discriminateur d’application par défaut pour l’environnement. L’exécution d’une application dans plusieurs environnements dépasse le cadre de cet article.
Les packages NuGet suivants sont requis pour les extensions de protection des données utilisées dans cet article :
ProtectKeysWithAzureKeyVault
Connectez-vous à Azure à l’aide de l’interface CLI, par exemple :
az login
Pour gérer les clés avec Azure Key Vault, configurez le système avec ProtectKeysWithAzureKeyVault dans Program.cs
. blobUriWithSasToken
est l’URI complet dans lequel le fichier de clé doit être stocké. L’URI doit contenir le jeton SAS en tant que paramètre de chaîne de requête :
builder.Services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
Pour qu’une application communique et s’autorise avec KeyVault, le package Azure.Identity doit être ajouté.
Définissez l’emplacement de stockage du anneau de clés (par exemple, PersistKeysToAzureBlobStorage). L’emplacement doit être défini, car l’appel ProtectKeysWithAzureKeyVault
implémente un IXmlEncryptor qui désactive les paramètres de protection automatique des données, y compris l’emplacement de stockage du anneau de clés. L’exemple précédent utilise Stockage Blob Azure pour conserver le porte-clés. Pour plus d’informations, consultez Fournisseurs de stockage de clés : Stockage Azure. Vous pouvez également conserver le cercle de clés localement avec PersistKeysToFileSystem.
keyIdentifier
est l’identificateur de clé du coffre de clés utilisé pour le chiffrement de clé. Par exemple, une clé créée dans le coffre de clés nommée dataprotection
dans contosokeyvault
a l’identificateur de clé https://contosokeyvault.vault.azure.net/keys/dataprotection/
. Fournissez à l’application les autorisations Get, Unwrap Key et Wrap Key pour le coffre de clés.
ProtectKeysWithAzureKeyVault
surcharge :
- ProtectKeysWithAzureKeyVault(IDataProtectionBuilder, Uri, TokenCredential) autorise l’utilisation d’un URI keyIdentifier et d’un tokenCredential pour permettre au système de protection des données d’utiliser le coffre de clés.
- ProtectKeysWithAzureKeyVault(IDataProtectionBuilder, String, IKeyEncryptionKeyResolver) permet d’utiliser une chaîne keyIdentifier et IKeyEncryptionKeyResolver pour permettre au système de protection des données d’utiliser le coffre de clés.
Si l’application utilise les packages Azure plus anciens (Microsoft.AspNetCore.DataProtection.AzureStorage et Microsoft.AspNetCore.DataProtection.AzureKeyVault), nous vous recommandons de supprimer ces références et de mettre à niveau vers Azure.Extensions.AspNetCore.DataProtection.Blobs et Azure.Extensions.AspNetCore.DataProtection.Keys. Ces packages sont l’endroit où de nouvelles mises à jour sont fournies et résolvent certains problèmes de sécurité et de stabilité clés avec les anciens packages.
builder.Services.AddDataProtection()
// This blob must already exist before the application is run
.PersistKeysToAzureBlobStorage("<storageAccountConnectionString", "<containerName>", "<blobName>")
// Removing this line below for an initial run will ensure the file is created correctly
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
PersistKeysToFileSystem
Pour stocker des clés sur un partage UNC au lieu de l’emplacement par défaut %LOCALAPPDATA%, configurez le système avec PersistKeysToFileSystem :
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
Avertissement
Si vous modifiez l’emplacement de persistance des clés, le système ne chiffre plus automatiquement les clés au rest, car il ne sait pas si DPAPI est un mécanisme de chiffrement approprié.
PersistKeysToDbContext
Pour stocker des clés dans une base de données à l’aide d’EntityFramework, configurez le système avec le package Microsoft.AspNetCore.DataProtection.EntityFrameworkCore :
builder.Services.AddDataProtection()
.PersistKeysToDbContext<SampleDbContext>();
Le code précédent stocke les clés dans la base de données configurée. Le contexte de base de données utilisé doit implémenter IDataProtectionKeyContext
. IDataProtectionKeyContext
expose la propriété DataProtectionKeys
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
Cette propriété représente la table dans laquelle les clés sont stockées. Créez la table manuellement ou avec DbContext
Migrations. Pour plus d’informations, consultez DataProtectionKey.
ProtectKeysWith*
Vous pouvez configurer le système pour protéger les clés au rest en appelant l’une des API de configuration ProtectKeysWith*. Considérez l’exemple ci-dessous, qui stocke les clés sur un partage UNC et chiffre ces clés au rest avec un certificat X.509 spécifique :
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);
Vous pouvez fournir un X509Certificate2 à ProtectKeysWithCertificate, tel qu’un certificat chargé à partir d’un fichier :
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));
Pour plus d’exemples et une discussion sur les mécanismes de chiffrement de clés intégrés, consultez la section Chiffrement de clé au Rest.
UnprotectKeysWithAnyCertificate
Vous pouvez faire pivoter les certificats et déchiffrer les clés au rest à l’aide d’un tableau de certificats X509Certificate2 avec UnprotectKeysWithAnyCertificate :
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]))
.UnprotectKeysWithAnyCertificate(
new X509Certificate2("certificate_1.pfx", builder.Configuration["CertificatePassword_1"]),
new X509Certificate2("certificate_2.pfx", builder.Configuration["CertificatePassword_2"]));
SetDefaultKeyLifetime
Pour configurer le système afin qu’il utilise une durée de vie de clé de 14 jours au lieu des 90 jours par défaut, utilisez SetDefaultKeyLifetime :
builder.Services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
SetApplicationName
Par défaut, le système de protection des données isole les applications les unes des autres en fonction de leurs chemins racine de contenu, même si elles partagent le même référentiel de clés physiques. Cette isolation empêche les applications de comprendre les charges utiles protégées des autres.
Pour partager des charges utiles protégées entre les applications :
- Configurez SetApplicationName dans chaque application avec la même valeur.
- Utilisez la même version de la pile d’API Protection des données dans les applications. Effectuez l’une des opérations suivantes dans les fichiers projet des applications :
- Référencez la même version du framework partagé via le métapaquet Microsoft.AspNetCore.App.
- Référencez la même version du package de protection des données.
builder.Services.AddDataProtection()
.SetApplicationName("<sharedApplicationName>");
SetApplicationName définit DataProtectionOptions.ApplicationDiscriminatoren interne. À des fins de résolution des problèmes, la valeur attribuée au discriminateur par l’infrastructure peut être journalisée avec le code suivant placé après l’intégration WebApplicationde Program.cs
:
var discriminator = app.Services.GetRequiredService<IOptions<DataProtectionOptions>>()
.Value.ApplicationDiscriminator;
app.Logger.LogInformation("ApplicationDiscriminator: {ApplicationDiscriminator}", discriminator);
Pour plus d’informations sur l’utilisation du discriminateur, consultez les sections suivantes plus loin dans cet article :
Avertissement
Dans .NET 6, WebApplicationBuilder normalise le chemin racine du contenu pour qu'il se termine par un DirectorySeparatorChar. Par exemple, sur Windows, le chemin d’accès racine du contenu se termine par \
et sur Linux /
. Les autres hôtes ne normalisent pas le chemin d’accès. La plupart des applications qui migrent à partir de HostBuilder ou WebHostBuilder ne partagent pas le même nom d’application, car elles n’auront pas le nom de fin DirectorySeparatorChar
. Pour contourner ce problème, supprimez le caractère de séparateur de répertoire et définissez manuellement le nom de l’application, comme indiqué dans le code suivant :
using Microsoft.AspNetCore.DataProtection;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
var trimmedContentRootPath = builder.Environment.ContentRootPath.TrimEnd(Path.DirectorySeparatorChar);
builder.Services.AddDataProtection()
.SetApplicationName(trimmedContentRootPath);
var app = builder.Build();
app.MapGet("/", () => Assembly.GetEntryAssembly()!.GetName().Name);
app.Run();
DisableAutomaticKeyGeneration
Vous pouvez avoir un scénario dans lequel vous ne souhaitez pas qu’une application restaure automatiquement les clés (créer de nouvelles clés) à mesure qu’elles approchent de l’expiration. Un exemple de ce scénario peut être les applications configurées dans une relation primaire/secondaire, où seule l’application principale est responsable des problèmes de gestion des clés et où les applications secondaires ont simplement une vue en lecture seule de l’anneau de clés. Les applications secondaires peuvent être configurées pour traiter l’anneau de clés en lecture seule en configurant le système avec DisableAutomaticKeyGeneration :
builder.Services.AddDataProtection()
.DisableAutomaticKeyGeneration();
Isolation par application
Lorsque le système de protection des données est fourni par un hôte ASP.NET Core, il isole automatiquement les applications les unes des autres, même si ces applications s’exécutent sous le même compte de processus de travail et utilisent le même master matériel de clé. Ceci est similaire au modificateur IsolateApps de l’élément <machineKey>
System.Web.
Le mécanisme d’isolation fonctionne en considérant chaque application sur l’ordinateur local comme un locataire unique. Par conséquent, le IDataProtector rooté d’une application donnée inclut automatiquement l’ID d’application comme un discriminateur (ApplicationDiscriminator). L’ID unique de l’application est le chemin physique de l’application :
- Pour les applications hébergées dans IIS, l’ID unique est le chemin physique IIS de l’application. Si une application est déployée dans un environnement de batterie de serveurs web, cette valeur est stable en supposant que les environnements IIS sont configurés de la même manière sur toutes les machines de la batterie de serveurs web.
- Pour les applications auto-hébergées s’exécutant sur le Kestrel serveur, l’ID unique est le chemin physique de l’application sur le disque.
L’identificateur unique est conçu pour survivre aux réinitialisations, à la fois de l’application individuelle et de la machine elle-même.
Ce mécanisme d’isolation suppose que les applications ne sont pas malveillantes. Une application malveillante peut toujours avoir un impact sur toute autre application s’exécutant sous le même compte de processus de travail. Dans un environnement d’hébergement partagé où les applications ne sont pas approuvées mutuellement, le fournisseur d’hébergement doit prendre des mesures pour garantir l’isolation au niveau du système d’exploitation entre les applications, y compris la séparation des dépôts de clés sous-jacents des applications.
Si le système de protection des données n’est pas fourni par un hôte ASP.NET Core (par exemple, si vous l’instanciez via le type concret DataProtectionProvider
), l’isolation de l’application est désactivée par défaut. Lorsque l’isolation d’application est désactivée, toutes les applications soutenues par le même matériel de clé peuvent partager des charges utiles tant qu’elles fournissent les objectifs appropriés. Pour fournir une isolation d’application dans cet environnement, appelez la méthode SetApplicationName
sur l’objet de configuration et fournissez un nom unique pour chaque application.
Protection des données et isolation des applications
Tenez compte des points suivants pour l’isolation des applications :
Lorsque plusieurs applications sont pointées vers le même référentiel de clés, l’intention est que les applications partagent le même master matériel clé. La protection des données est développée en supposant que toutes les applications partageant un anneau de clés peuvent accéder à tous les éléments de cet anneau de clés. L’identificateur unique de l’application est utilisé pour isoler les clés spécifiques à l’application dérivées des clés fournies par l’anneau de clés. Il ne s’attend pas à ce que les autorisations de niveau élément, telles que celles fournies par Azure KeyVault, soient utilisées pour appliquer une isolation supplémentaire. La tentative d’autorisations au niveau de l’élément génère des erreurs d’application. Si vous ne souhaitez pas vous fier à l’isolation intégrée de l’application, des emplacements de magasin de clés distincts doivent être utilisés et non partagés entre les applications.
Le discriminateur d’application (ApplicationDiscriminator) permet à différentes applications de partager le même master matériel clé, mais de conserver leurs charges utiles de chiffrement distinctes les unes des autres. Pour que les applications puissent lire les charges utiles de chiffrement de l’autre, elles doivent avoir le même discriminateur d’application, qui peut être défini en appelant
SetApplicationName
.Si une application est compromise (par exemple, par une attaque RCE), tout matériau de clé principale accessible à cette application doit également être considéré comme compromis, quel que soit son état de protection au rest. Cela implique que si deux applications sont pointées vers le même dépôt, même si elles utilisent des discriminateurs d’application différents, une compromission de l’une d’elles équivaut fonctionnellement à une compromission des deux.
Cette clause « fonctionnellement équivalente à un compromis des deux » est valable même si les deux applications utilisent des mécanismes différents pour la protection des clés au rest. En règle générale, il ne s’agit pas d’une configuration attendue. Le mécanisme de protection au rest est destiné à fournir une protection dans le cas où un cyberattaquant obtient un accès en lecture au dépôt. Un cyberattaquant qui obtient un accès en écriture au dépôt (peut-être parce qu’il a obtenu l’autorisation d’exécution de code au sein d’une application) peut insérer des clés malveillantes dans le stockage. Le système de protection des données ne fournit intentionnellement pas de protection contre un cyberattaquant qui obtient un accès en écriture au dépôt de clés.
Si les applications doivent rester vraiment isolées les unes des autres, elles doivent utiliser différents référentiels de clés. Cela s’inscrit naturellement dans la définition de « isolé ». Les applications ne sont pas isolées si elles disposent toutes d’un accès en lecture et en écriture aux magasins de données des autres.
Modification d’algorithmes avec UseCryptographicAlgorithms
La pile de protection des données vous permet de modifier l’algorithme par défaut utilisé par les clés nouvellement générées. Le moyen le plus simple d’effectuer cette opération consiste à appeler UseCryptographicAlgorithms à partir du rappel de configuration :
builder.Services.AddDataProtection()
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
Le EncryptionAlgorithm par défaut est AES-256-CBC, et l’élément ValidationAlgorithm par défaut est HMACSHA256. La stratégie par défaut peut être définie par un administrateur système via une stratégie à l’échelle de l’ordinateur, mais un appel explicite à UseCryptographicAlgorithms
remplace la stratégie par défaut.
L’appel UseCryptographicAlgorithms
vous permet de spécifier l’algorithme souhaité à partir d’une liste prédéfinie intégrée. Vous n’avez pas à vous soucier de l’implémentation de l’algorithme. Dans le scénario ci-dessus, le système de protection des données tente d’utiliser l’implémentation CNG d’AES en cas d’exécution sur Windows. Sinon, elle revient à la classe managée System.Security.Cryptography.Aes.
Vous pouvez spécifier manuellement une implémentation via un appel à UseCustomCryptographicAlgorithms.
Conseil
La modification des algorithmes n’affecte pas les clés existantes dans l’anneau de clés. Elle affecte uniquement les clés nouvellement générées.
Spécification d’algorithmes managés personnalisés
Pour spécifier des algorithmes managés personnalisés, créez une instance ManagedAuthenticatedEncryptorConfiguration qui pointe vers les types d’implémentation :
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new ManagedAuthenticatedEncryptorConfiguration
{
// A type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// A type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
En règle générale, les propriétés *Type doivent pointer vers des implémentations concrètes et instanciables (via un ctor public sans paramètre) de SymmetricAlgorithm et KeyedHashAlgorithm, bien que les cas spéciaux du système, certaines valeurs comme typeof(Aes)
pour des raisons pratiques.
Notes
SymmetricAlgorithm doit avoir une longueur de clé de ≥ 128 bits et une taille de bloc de ≥ 64 bits, et il doit prendre en charge le chiffrement en mode CBC avec remplissage PKCS #7. KeyedHashAlgorithm doit avoir une taille de synthèse de >= 128 bits, et il doit prendre en charge des clés de longueur égale à la longueur de synthèse de l’algorithme de hachage. KeyedHashAlgorithm n’est pas strictement requis pour être HMAC.
Spécification d’algorithmes CNG Windows personnalisés
Pour spécifier un algorithme CNG Windows personnalisé à l’aide du chiffrement en mode CBC avec validation HMAC, créez une instance CngCbcAuthenticatedEncryptorConfiguration qui contient les informations algorithmiques :
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngCbcAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// Passed to BCryptOpenAlgorithmProvider
HashAlgorithm = "SHA256",
HashAlgorithmProvider = null
});
Notes
L’algorithme de chiffrement par blocs symétriques doit avoir une longueur de clé de >= 128 bits, une taille de bloc de >= 64 bits, et il doit prendre en charge le chiffrement en mode CBC avec remplissage PKCS #7. L’algorithme de hachage doit avoir une taille de synthèse de >= 128 bits et doit prendre en charge l’ouverture avec l’indicateur BCRYPT_ALG_HANDLE_HMAC_FLAG. Les propriétés du fournisseur peuvent être définies sur null pour utiliser le fournisseur par défaut pour l’algorithme spécifié. Pour plus d'informations, voir la documentation de BCryptOpenAlgorithmProvider.
Pour spécifier un algorithme CNG Windows personnalisé à l’aide du chiffrement Galois/Counter Mode avec validation, créez une instance CngGcmAuthenticatedEncryptorConfiguration qui contient les informations algorithmiques :
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngGcmAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
Notes
L’algorithme de chiffrement par blocs symétriques doit avoir une longueur de clé de >= 128 bits, une taille de bloc d’exactement 128 bits, et il doit prendre en charge le chiffrement GCM. Vous pouvez définir la propriété sur EncryptionAlgorithmProvider null pour utiliser le fournisseur par défaut pour l’algorithme spécifié. Pour plus d'informations, voir la documentation de BCryptOpenAlgorithmProvider.
Spécification d’autres algorithmes personnalisés
Bien qu’il ne soit pas exposé en tant qu’API de première classe, le système de protection des données est suffisamment extensible pour permettre de spécifier presque n’importe quel type d’algorithme. Par exemple, il est possible de conserver toutes les clés contenues dans un module de sécurité matérielle (HSM) et de fournir une implémentation personnalisée des principales routines de chiffrement et de déchiffrement. Pour plus d’informations, consultez IAuthenticatedEncryptordansExtensibilité du chiffrement cœur.
Conservation des clés lors de l’hébergement dans un conteneur Docker
Lors de l’hébergement dans un conteneur Docker, les clés doivent être conservées dans :
- Un Dossier qui est un volume Docker qui persiste au-delà de la durée de vie du conteneur, tel qu’un volume partagé ou un volume monté sur un hôte.
- Un fournisseur externe, tel que Stockage Blob Azure (illustré dans la section
ProtectKeysWithAzureKeyVault
) ou Redis.
Conservation des clés avec Redis
Seules les versions de Redis prenant en charge la persistance des données Redis doivent être utilisées pour stocker des clés. Le stockage Blob Azure est persistant et peut être utilisé pour stocker des clés. Pour plus d’informations, consultez ce problème GitHub.
Journalisation de DataProtection
Activez Information
la journalisation de niveau de DataProtection pour faciliter le diagnostic du problème. Le fichier suivant appsettings.json
active la journalisation des informations de l’API DataProtection :
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.DataProtection": "Information"
}
},
"AllowedHosts": "*"
}
Pour plus d’informations sur la journalisation, consultez Journalisation dans .NET Core et ASP.NET Core.
Ressources supplémentaires
- Scénarios non compatibles avec l’injection de dépendances pour la protection des données dans ASP.NET Core
- Prise en charge de la stratégie au niveau de l’ordinateur de protection des données dans ASP.NET Core
- Héberger ASP.NET Core dans une batterie de serveurs web
- Fournisseurs de stockage de clé dans ASP.NET Core
Lorsque le système de protection des données est initialisé, il applique les paramètres par défaut en fonction de l’environnement opérationnel. Ces paramètres sont appropriés pour les applications s’exécutant sur un seul ordinateur. Toutefois, il existe des cas où un développeur peut vouloir modifier les paramètres par défaut :
- L’application est répartie sur plusieurs ordinateurs.
- Pour des raisons de conformité.
Pour ces scénarios, le système de protection des données offre une API de configuration riche.
Avertissement
Comme pour les fichiers de configuration, l’anneau de clés de protection des données doit être protégé à l’aide des autorisations appropriées. Vous pouvez choisir de chiffrer les clés au rest, mais cela n’empêche pas les cyberattaquants de créer de nouvelles clés. Par conséquent, la sécurité de votre application est affectée. L’emplacement de stockage configuré avec Data Protection doit avoir son accès limité à l’application elle-même, comme vous le feriez pour protéger les fichiers de configuration. Par exemple, si vous choisissez de stocker votre anneau de clés sur le disque, utilisez les autorisations du système de fichiers. Vérifiez que seule l’identity sous laquelle votre application web s’exécute dispose d’un accès en lecture, écriture et création à ce répertoire. Si vous utilisez Stockage Blob Azure, seule l’application web doit avoir la possibilité de lire, d’écrire ou de créer de nouvelles entrées dans le magasin d’objets blob, etc.
La méthode d’extension AddDataProtection retourne un IDataProtectionBuilder. IDataProtectionBuilder
expose les méthodes d’extension que vous pouvez chaîner ensemble pour configurer les options de protection des données.
Les packages NuGet suivants sont requis pour les extensions de protection des données utilisées dans cet article :
ProtectKeysWithAzureKeyVault
Connectez-vous à Azure à l’aide de l’interface CLI, par exemple :
az login
Pour stocker des clés dans Azure Key Vault, configurez le système avec ProtectKeysWithAzureKeyVault dans la classe Startup
. blobUriWithSasToken
est l’URI complet dans lequel le fichier de clé doit être stocké. L’URI doit contenir le jeton SAS en tant que paramètre de chaîne de requête :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
}
Pour qu’une application communique et s’autorise avec KeyVault, le package Azure.Identity doit être ajouté.
Définissez l’emplacement de stockage du anneau de clés (par exemple, PersistKeysToAzureBlobStorage). L’emplacement doit être défini, car l’appel ProtectKeysWithAzureKeyVault
implémente un IXmlEncryptor qui désactive les paramètres de protection automatique des données, y compris l’emplacement de stockage du anneau de clés. L’exemple précédent utilise Stockage Blob Azure pour conserver le porte-clés. Pour plus d’informations, consultez Fournisseurs de stockage de clés : Stockage Azure. Vous pouvez également conserver le cercle de clés localement avec PersistKeysToFileSystem.
keyIdentifier
est l’identificateur de clé du coffre de clés utilisé pour le chiffrement de clé. Par exemple, une clé créée dans le coffre de clés nommée dataprotection
dans contosokeyvault
a l’identificateur de clé https://contosokeyvault.vault.azure.net/keys/dataprotection/
. Fournissez à l’application les autorisations Get, Unwrap Key et Wrap Key pour le coffre de clés.
ProtectKeysWithAzureKeyVault
surcharge :
- ProtectKeysWithAzureKeyVault(IDataProtectionBuilder, Uri, TokenCredential) autorise l’utilisation d’un URI keyIdentifier et d’un tokenCredential pour permettre au système de protection des données d’utiliser le coffre de clés.
- ProtectKeysWithAzureKeyVault(IDataProtectionBuilder, String, IKeyEncryptionKeyResolver) permet d’utiliser une chaîne keyIdentifier et IKeyEncryptionKeyResolver pour permettre au système de protection des données d’utiliser le coffre de clés.
Si l’application utilise les packages Azure plus anciens (Microsoft.AspNetCore.DataProtection.AzureStorage et Microsoft.AspNetCore.DataProtection.AzureKeyVault), nous vous recommandons de supprimer ces références et de mettre à niveau vers Azure.Extensions.AspNetCore.DataProtection.Blobs et Azure.Extensions.AspNetCore.DataProtection.Keys. Ces packages sont l’endroit où de nouvelles mises à jour sont fournies et résolvent certains problèmes de sécurité et de stabilité clés avec les anciens packages.
services.AddDataProtection()
//This blob must already exist before the application is run
.PersistKeysToAzureBlobStorage("<storage account connection string", "<key store container name>", "<key store blob name>")
//Removing this line below for an initial run will ensure the file is created correctly
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
Avertissement
Cet article montre l’utilisation de chaîne de connexion s. Avec une base de données locale, l’utilisateur n’a pas besoin d’être authentifié, mais en production, les chaîne de connexion incluent parfois un mot de passe pour s’authentifier. Les informations d’identification de mot de passe du propriétaire de la ressource (ROPC) constituent un risque de sécurité qui doit être évité dans les bases de données de production. Les applications de production doivent utiliser le flux d’authentification le plus sécurisé disponible. Pour plus d’informations sur l’authentification des applications déployées pour tester ou produire des environnements, consultez Flux d’authentification sécurisés.
PersistKeysToFileSystem
Pour stocker des clés sur un partage UNC au lieu de l’emplacement par défaut %LOCALAPPDATA%, configurez le système avec PersistKeysToFileSystem :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
}
Avertissement
Si vous modifiez l’emplacement de persistance des clés, le système ne chiffre plus automatiquement les clés au rest, car il ne sait pas si DPAPI est un mécanisme de chiffrement approprié.
PersistKeysToDbContext
Pour stocker des clés dans une base de données à l’aide d’EntityFramework, configurez le système avec le package Microsoft.AspNetCore.DataProtection.EntityFrameworkCore :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToDbContext<DbContext>()
}
Le code précédent stocke les clés dans la base de données configurée. Le contexte de base de données utilisé doit implémenter IDataProtectionKeyContext
. IDataProtectionKeyContext
expose la propriété DataProtectionKeys
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
Cette propriété représente la table dans laquelle les clés sont stockées. Créez la table manuellement ou avec DbContext
Migrations. Pour plus d’informations, consultez DataProtectionKey.
ProtectKeysWith*
Vous pouvez configurer le système pour protéger les clés au rest en appelant l’une des API de configuration ProtectKeysWith*. Considérez l’exemple ci-dessous, qui stocke les clés sur un partage UNC et chiffre ces clés au rest avec un certificat X.509 spécifique :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(Configuration["Thumbprint"]);
}
Vous pouvez fournir un X509Certificate2 à ProtectKeysWithCertificate, tel qu’un certificat chargé à partir d’un fichier :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", Configuration["Thumbprint"]));
}
Pour plus d’exemples et une discussion sur les mécanismes de chiffrement de clés intégrés, consultez la section Chiffrement de clé au Rest.
UnprotectKeysWithAnyCertificate
Vous pouvez faire pivoter les certificats et déchiffrer les clés au rest à l’aide d’un tableau de certificats X509Certificate2 avec UnprotectKeysWithAnyCertificate :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", Configuration["MyPasswordKey"));
.UnprotectKeysWithAnyCertificate(
new X509Certificate2("certificate_old_1.pfx", Configuration["MyPasswordKey_1"]),
new X509Certificate2("certificate_old_2.pfx", Configuration["MyPasswordKey_2"]));
}
SetDefaultKeyLifetime
Pour configurer le système afin qu’il utilise une durée de vie de clé de 14 jours au lieu des 90 jours par défaut, utilisez SetDefaultKeyLifetime :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
}
SetApplicationName
Par défaut, le système de protection des données isole les applications les unes des autres en fonction de leurs chemins racine de contenu, même si elles partagent le même référentiel de clés physiques. Cette isolation empêche les applications de comprendre les charges utiles protégées des autres.
Pour partager des charges utiles protégées entre les applications :
- Configurez SetApplicationName dans chaque application avec la même valeur.
- Utilisez la même version de la pile d’API Protection des données dans les applications. Effectuez l’une des opérations suivantes dans les fichiers projet des applications :
- Référencez la même version du framework partagé via le métapaquet Microsoft.AspNetCore.App.
- Référencez la même version du package de protection des données.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetApplicationName("shared app name");
}
SetApplicationName définit DataProtectionOptions.ApplicationDiscriminatoren interne. Pour plus d’informations sur l’utilisation du discriminateur, consultez les sections suivantes plus loin dans cet article :
DisableAutomaticKeyGeneration
Vous pouvez avoir un scénario dans lequel vous ne souhaitez pas qu’une application restaure automatiquement les clés (créer de nouvelles clés) à mesure qu’elles approchent de l’expiration. Un exemple de ce scénario peut être les applications configurées dans une relation primaire/secondaire, où seule l’application principale est responsable des problèmes de gestion des clés et où les applications secondaires ont simplement une vue en lecture seule de l’anneau de clés. Les applications secondaires peuvent être configurées pour traiter l’anneau de clés en lecture seule en configurant le système avec DisableAutomaticKeyGeneration :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.DisableAutomaticKeyGeneration();
}
Isolation par application
Lorsque le système de protection des données est fourni par un hôte ASP.NET Core, il isole automatiquement les applications les unes des autres, même si ces applications s’exécutent sous le même compte de processus de travail et utilisent le même master matériel de clé. Ceci est similaire au modificateur IsolateApps de l’élément <machineKey>
System.Web.
Le mécanisme d’isolation fonctionne en considérant chaque application sur l’ordinateur local comme un locataire unique. Par conséquent, le IDataProtector rooté d’une application donnée inclut automatiquement l’ID d’application comme un discriminateur (ApplicationDiscriminator). L’ID unique de l’application est le chemin physique de l’application :
- Pour les applications hébergées dans IIS, l’ID unique est le chemin physique IIS de l’application. Si une application est déployée dans un environnement de batterie de serveurs web, cette valeur est stable en supposant que les environnements IIS sont configurés de la même manière sur toutes les machines de la batterie de serveurs web.
- Pour les applications auto-hébergées s’exécutant sur le Kestrel serveur, l’ID unique est le chemin physique de l’application sur le disque.
L’identificateur unique est conçu pour survivre aux réinitialisations, à la fois de l’application individuelle et de la machine elle-même.
Ce mécanisme d’isolation suppose que les applications ne sont pas malveillantes. Une application malveillante peut toujours avoir un impact sur toute autre application s’exécutant sous le même compte de processus de travail. Dans un environnement d’hébergement partagé où les applications ne sont pas approuvées mutuellement, le fournisseur d’hébergement doit prendre des mesures pour garantir l’isolation au niveau du système d’exploitation entre les applications, y compris la séparation des dépôts de clés sous-jacents des applications.
Si le système de protection des données n’est pas fourni par un hôte ASP.NET Core (par exemple, si vous l’instanciez via le type concret DataProtectionProvider
), l’isolation de l’application est désactivée par défaut. Lorsque l’isolation d’application est désactivée, toutes les applications soutenues par le même matériel de clé peuvent partager des charges utiles tant qu’elles fournissent les objectifs appropriés. Pour fournir une isolation d’application dans cet environnement, appelez la méthode SetApplicationName sur l’objet de configuration et fournissez un nom unique pour chaque application.
Protection des données et isolation des applications
Tenez compte des points suivants pour l’isolation des applications :
Lorsque plusieurs applications sont pointées vers le même référentiel de clés, l’intention est que les applications partagent le même master matériel clé. La protection des données est développée en supposant que toutes les applications partageant un anneau de clés peuvent accéder à tous les éléments de cet anneau de clés. L’identificateur unique de l’application est utilisé pour isoler les clés spécifiques à l’application dérivées des clés fournies par l’anneau de clés. Il ne s’attend pas à ce que les autorisations de niveau élément, telles que celles fournies par Azure KeyVault, soient utilisées pour appliquer une isolation supplémentaire. La tentative d’autorisations au niveau de l’élément génère des erreurs d’application. Si vous ne souhaitez pas vous fier à l’isolation intégrée de l’application, des emplacements de magasin de clés distincts doivent être utilisés et non partagés entre les applications.
Le discriminateur d’application (ApplicationDiscriminator) permet à différentes applications de partager le même master matériel clé, mais de conserver leurs charges utiles de chiffrement distinctes les unes des autres. Pour que les applications puissent lire les charges utiles de chiffrement de l’autre, elles doivent avoir le même discriminateur d’application, qui peut être défini en appelant
SetApplicationName
.Si une application est compromise (par exemple, par une attaque RCE), tout matériau de clé principale accessible à cette application doit également être considéré comme compromis, quel que soit son état de protection au rest. Cela implique que si deux applications sont pointées vers le même dépôt, même si elles utilisent des discriminateurs d’application différents, une compromission de l’une d’elles équivaut fonctionnellement à une compromission des deux.
Cette clause « fonctionnellement équivalente à un compromis des deux » est valable même si les deux applications utilisent des mécanismes différents pour la protection des clés au rest. En règle générale, il ne s’agit pas d’une configuration attendue. Le mécanisme de protection au rest est destiné à fournir une protection dans le cas où un cyberattaquant obtient un accès en lecture au dépôt. Un cyberattaquant qui obtient un accès en écriture au dépôt (peut-être parce qu’il a obtenu l’autorisation d’exécution de code au sein d’une application) peut insérer des clés malveillantes dans le stockage. Le système de protection des données ne fournit intentionnellement pas de protection contre un cyberattaquant qui obtient un accès en écriture au dépôt de clés.
Si les applications doivent rester vraiment isolées les unes des autres, elles doivent utiliser différents référentiels de clés. Cela s’inscrit naturellement dans la définition de « isolé ». Les applications ne sont pas isolées si elles disposent toutes d’un accès en lecture et en écriture aux magasins de données des autres.
Modification d’algorithmes avec UseCryptographicAlgorithms
La pile de protection des données vous permet de modifier l’algorithme par défaut utilisé par les clés nouvellement générées. Le moyen le plus simple d’effectuer cette opération consiste à appeler UseCryptographicAlgorithms à partir du rappel de configuration :
services.AddDataProtection()
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
Le EncryptionAlgorithm par défaut est AES-256-CBC, et l’élément ValidationAlgorithm par défaut est HMACSHA256. La stratégie par défaut peut être définie par un administrateur système via une stratégie à l’échelle de l’ordinateur, mais un appel explicite à UseCryptographicAlgorithms
remplace la stratégie par défaut.
L’appel UseCryptographicAlgorithms
vous permet de spécifier l’algorithme souhaité à partir d’une liste prédéfinie intégrée. Vous n’avez pas à vous soucier de l’implémentation de l’algorithme. Dans le scénario ci-dessus, le système de protection des données tente d’utiliser l’implémentation CNG d’AES en cas d’exécution sur Windows. Sinon, elle revient à la classe managée System.Security.Cryptography.Aes.
Vous pouvez spécifier manuellement une implémentation via un appel à UseCustomCryptographicAlgorithms.
Conseil
La modification des algorithmes n’affecte pas les clés existantes dans l’anneau de clés. Elle affecte uniquement les clés nouvellement générées.
Spécification d’algorithmes managés personnalisés
Pour spécifier des algorithmes managés personnalisés, créez une instance ManagedAuthenticatedEncryptorConfiguration qui pointe vers les types d’implémentation :
serviceCollection.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new ManagedAuthenticatedEncryptorConfiguration()
{
// A type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// A type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
En règle générale, les propriétés *Type doivent pointer vers des implémentations concrètes et instanciables (via un ctor public sans paramètre) de SymmetricAlgorithm et KeyedHashAlgorithm, bien que les cas spéciaux du système, certaines valeurs comme typeof(Aes)
pour des raisons pratiques.
Notes
SymmetricAlgorithm doit avoir une longueur de clé de ≥ 128 bits et une taille de bloc de ≥ 64 bits, et il doit prendre en charge le chiffrement en mode CBC avec remplissage PKCS #7. KeyedHashAlgorithm doit avoir une taille de synthèse de >= 128 bits, et il doit prendre en charge des clés de longueur égale à la longueur de synthèse de l’algorithme de hachage. KeyedHashAlgorithm n’est pas strictement requis pour être HMAC.
Spécification d’algorithmes CNG Windows personnalisés
Pour spécifier un algorithme CNG Windows personnalisé à l’aide du chiffrement en mode CBC avec validation HMAC, créez une instance CngCbcAuthenticatedEncryptorConfiguration qui contient les informations algorithmiques :
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngCbcAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// Passed to BCryptOpenAlgorithmProvider
HashAlgorithm = "SHA256",
HashAlgorithmProvider = null
});
Notes
L’algorithme de chiffrement par blocs symétriques doit avoir une longueur de clé de >= 128 bits, une taille de bloc de >= 64 bits, et il doit prendre en charge le chiffrement en mode CBC avec remplissage PKCS #7. L’algorithme de hachage doit avoir une taille de synthèse de >= 128 bits et doit prendre en charge l’ouverture avec l’indicateur BCRYPT_ALG_HANDLE_HMAC_FLAG. Les propriétés du fournisseur peuvent être définies sur null pour utiliser le fournisseur par défaut pour l’algorithme spécifié. Pour plus d'informations, voir la documentation de BCryptOpenAlgorithmProvider.
Pour spécifier un algorithme CNG Windows personnalisé à l’aide du chiffrement Galois/Counter Mode avec validation, créez une instance CngGcmAuthenticatedEncryptorConfiguration qui contient les informations algorithmiques :
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngGcmAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
Notes
L’algorithme de chiffrement par blocs symétriques doit avoir une longueur de clé de >= 128 bits, une taille de bloc d’exactement 128 bits, et il doit prendre en charge le chiffrement GCM. Vous pouvez définir la propriété sur EncryptionAlgorithmProvider null pour utiliser le fournisseur par défaut pour l’algorithme spécifié. Pour plus d'informations, voir la documentation de BCryptOpenAlgorithmProvider.
Spécification d’autres algorithmes personnalisés
Bien qu’il ne soit pas exposé en tant qu’API de première classe, le système de protection des données est suffisamment extensible pour permettre de spécifier presque n’importe quel type d’algorithme. Par exemple, il est possible de conserver toutes les clés contenues dans un module de sécurité matérielle (HSM) et de fournir une implémentation personnalisée des principales routines de chiffrement et de déchiffrement. Pour plus d’informations, consultez IAuthenticatedEncryptordansExtensibilité du chiffrement cœur.
Conservation des clés lors de l’hébergement dans un conteneur Docker
Lors de l’hébergement dans un conteneur Docker, les clés doivent être conservées dans :
- Un Dossier qui est un volume Docker qui persiste au-delà de la durée de vie du conteneur, tel qu’un volume partagé ou un volume monté sur un hôte.
- Un fournisseur externe, tel que Stockage Blob Azure (illustré dans la section
ProtectKeysWithAzureKeyVault
) ou Redis.
Conservation des clés avec Redis
Seules les versions de Redis prenant en charge la persistance des données Redis doivent être utilisées pour stocker des clés. Le stockage Blob Azure est persistant et peut être utilisé pour stocker des clés. Pour plus d’informations, consultez ce problème GitHub.
Journalisation de DataProtection
Activez Information
la journalisation de niveau de DataProtection pour faciliter le diagnostic du problème. Le fichier suivant appsettings.json
active la journalisation des informations de l’API DataProtection :
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.DataProtection": "Information"
}
}
}
Pour plus d’informations sur la journalisation, consultez Journalisation dans .NET Core et ASP.NET Core.
Ressources supplémentaires
- Scénarios non compatibles avec l’injection de dépendances pour la protection des données dans ASP.NET Core
- Prise en charge de la stratégie au niveau de l’ordinateur de protection des données dans ASP.NET Core
- Héberger ASP.NET Core dans une batterie de serveurs web
- Fournisseurs de stockage de clé dans ASP.NET Core