Extensibilité de la gestion des clés dans ASP.NET Core
Lisez la section relative à la gestion des clés avant de lire cette section, car elle explique certains des concepts fondamentaux derrière ces API.
Avertissement : Les types qui implémentent l’une des interfaces suivantes doivent être thread-safe pour plusieurs appelants.
Clé :
L’interface IKey
est la représentation de base d’une clé dans le système de chiffrement. Le terme clé est utilisé ici au sens abstrait, et non au sens littéral de « matériel de clé de chiffrement ». Une clé se caractérise par les propriétés suivantes :
Dates d’activation, de création et d’expiration
État de révocation.
Identificateur de clé (GUID)
En outre, IKey
expose une méthode CreateEncryptor
qui peut être utilisée pour créer une instance IAuthenticatedEncryptor lié à cette clé.
En outre, IKey
expose une méthode CreateEncryptorInstance
qui peut être utilisée pour créer une instance IAuthenticatedEncryptor lié à cette clé.
Notes
Il n’existe aucune API pour récupérer le matériel de chiffrement brut d’une instance IKey
.
IKeyManager
L’interface IKeyManager
représente un objet responsable du stockage général des clés, de la récupération et de la manipulation. Il expose trois opérations de haut niveau :
Créez une clé et conservez-la dans le stockage.
Récupérez toutes les clés du stockage.
Révoquez une ou plusieurs clés et conservez les informations de révocation dans le stockage.
Avertissement
L’écriture d’un IKeyManager
est une tâche très avancée, et la majorité des développeurs ne doivent pas la tenter. Au lieu de cela, la plupart des développeurs doivent tirer parti des fonctionnalités offertes par la classe XmlKeyManager .
XmlKeyManager
Le type XmlKeyManager
est l’implémentation concrète dans la boîte de IKeyManager
. Il fournit plusieurs fonctionnalités utiles, y compris l’entiercement de clé et le chiffrement des clés au rest. Les clés de ce système sont représentées en tant qu’éléments XML (plus précisément, XElement).
XmlKeyManager
dépend de plusieurs autres composants au cours de l’exécution de ses tâches :
AlgorithmConfiguration
, qui dicte les algorithmes utilisés par les nouvelles clés.IXmlRepository
, qui contrôle l’emplacement où les clés sont conservées dans le stockage.IXmlEncryptor
[facultatif], qui autorise le chiffrement des clés au rest.IKeyEscrowSink
[facultatif], qui fournit des services d’entiercement de clé.
IXmlRepository
, qui contrôle l’emplacement où les clés sont conservées dans le stockage.IXmlEncryptor
[facultatif], qui autorise le chiffrement des clés au rest.IKeyEscrowSink
[facultatif], qui fournit des services d’entiercement de clé.
Vous trouverez ci-dessous des diagrammes généraux qui indiquent comment ces composants sont câblés ensemble dans XmlKeyManager
.
Création de clé / CreateNewKey
Dans l’implémentation de CreateNewKey
, le AlgorithmConfiguration
composant est utilisé pour créer un unique IAuthenticatedEncryptorDescriptor
, qui est ensuite sérialisé au format XML. Si un récepteur d’entiercement de clé est présent, le xml brut (non chiffré) est fourni au récepteur pour le stockage à long terme. Le code XML non chiffré est ensuite exécuté via un IXmlEncryptor
(si nécessaire) pour générer le document XML chiffré. Ce document chiffré est conservé dans le stockage à long terme via le IXmlRepository
. (Si aucun IXmlEncryptor
n’est configuré, le document non chiffré est conservé dans IXmlRepository
.)
Création de clé / CreateNewKey
Dans l’implémentation de CreateNewKey
, le IAuthenticatedEncryptorConfiguration
composant est utilisé pour créer un unique IAuthenticatedEncryptorDescriptor
, qui est ensuite sérialisé au format XML. Si un récepteur d’entiercement de clé est présent, le xml brut (non chiffré) est fourni au récepteur pour le stockage à long terme. Le code XML non chiffré est ensuite exécuté via un IXmlEncryptor
(si nécessaire) pour générer le document XML chiffré. Ce document chiffré est conservé dans le stockage à long terme via le IXmlRepository
. (Si aucun IXmlEncryptor
n’est configuré, le document non chiffré est conservé dans IXmlRepository
.)
Récupération de clé / GetAllKeys
Dans l’implémentation de GetAllKeys
, les documents XML représentant les clés et les révocations sont lus à partir du IXmlRepository
sous-jacent. Si ces documents sont chiffrés, le système les déchiffre automatiquement. XmlKeyManager
crée les instances appropriées IAuthenticatedEncryptorDescriptorDeserializer
pour désérialiser les documents en instances IAuthenticatedEncryptorDescriptor
, qui sont ensuite encapsulées dans des instances individuelles IKey
. Cette collection d’instances IKey
est retournée à l’appelant.
Vous trouverez plus d’informations sur les éléments XML particuliers dans le document sur le format de stockage de clé.
IXmlRepository
L’interface IXmlRepository
représente un type qui peut conserver du XML dans et récupérer du CODE à partir d’un magasin de stockage. Il expose deux API :
GetAllElements
:IReadOnlyCollection<XElement>
StoreElement(XElement element, string friendlyName)
Les implémentations de IXmlRepository
n’ont pas besoin d’analyser le code XML qui les traverse. Ils doivent traiter les documents XML comme opaques et laisser les couches supérieures se soucier de la génération et de l’analyse des documents.
Il existe quatre types de béton intégrés qui implémentent IXmlRepository
:
Pour plus d’informations, consultez le document fournisseurs de stockage de clés .
L’inscription d’un IXmlRepository
personnalisé est appropriée lors de l’utilisation d’un autre magasin de stockage (par exemple, Stockage Table Azure).
Pour modifier le dépôt par défaut à l’échelle de l’application, inscrivez une instance personnalisé IXmlRepository
:
services.Configure<KeyManagementOptions>(options => options.XmlRepository = new MyCustomXmlRepository());
services.AddSingleton<IXmlRepository>(new MyCustomXmlRepository());
IXmlEncryptor
L’interface IXmlEncryptor
représente un type qui peut chiffrer un élément XML en texte clair. Elle expose une seule API :
- Encrypt(XElement en texte brut) : EncryptedXmlInfo
Si un IAuthenticatedEncryptorDescriptor
sérialisé contient des éléments marqués comme « nécessite un chiffrement », XmlKeyManager
exécute ces éléments via la méthode IXmlEncryptor
configuréeEncrypt
et conserve l’élément chiffré plutôt que l’élément en texte clair dans IXmlRepository
. La sortie de la méthode Encrypt
est un objet EncryptedXmlInfo
. Cet objet est un wrapper qui contient à la fois le résultat chiffré XElement
et le type qui représente un IXmlDecryptor
qui peut être utilisé pour déchiffrer l’élément correspondant.
Il existe quatre types de béton intégrés qui implémentent IXmlEncryptor
:
Pour plus d’informations, consultez le document Chiffrement de clé au rest.
Pour modifier le mécanisme de chiffrement de clé au rest par défaut à l’échelle de l’application, inscrivez une instance personnalisée IXmlEncryptor
:
services.Configure<KeyManagementOptions>(options => options.XmlEncryptor = new MyCustomXmlEncryptor());
services.AddSingleton<IXmlEncryptor>(new MyCustomXmlEncryptor());
IXmlDecryptor
L’interface IXmlDecryptor
représente un type qui sait comment déchiffrer un XElement
qui a été chiffré via un IXmlEncryptor
. Elle expose une seule API :
- Decrypt(XElement encryptedElement) : XElement
La méthode Decrypt
annule le chiffrement effectué par IXmlEncryptor.Encrypt
. En règle générale, chaque implémentation concrète IXmlEncryptor
aura une implémentation concrète IXmlDecryptor
correspondante.
Les types qui implémentent IXmlDecryptor
doivent avoir l’un des deux constructeurs publics suivants :
- .ctor(IServiceProvider)
- .ctor()
Notes
Le IServiceProvider
passé au constructeur peut être null.
IKeyEscrowSink
L’interface IKeyEscrowSink
représente un type qui peut effectuer l’entiercement d’informations sensibles. Rappelez-vous que les descripteurs sérialisés peuvent contenir des informations sensibles (telles que du matériel de chiffrement), et c’est ce qui a conduit à l’introduction du type IXmlEncryptor en premier lieu. Toutefois, des accidents se produisent et les boucles de clés peuvent être supprimées ou endommagées.
L’interface d’entiercement fournit une trappe d’échappement d’urgence, ce qui permet d’accéder au code XML sérialisé brut avant qu’il ne soit transformé par n’importe quel IXmlEncryptor configuré. L’interface expose une seule API :
- Store(Guid keyId, élément XElement)
Il appartient à l’implémentation IKeyEscrowSink
de gérer l’élément fourni de manière sécurisée et cohérente avec la stratégie métier. Une implémentation possible pourrait être que le récepteur d’entiercement chiffre l’élément XML à l’aide d’un certificat X.509 d’entreprise connu où la clé privée du certificat a été séquestré ; le CertificateXmlEncryptor
type peut vous aider avec cela. L’implémentation IKeyEscrowSink
est également responsable de la persistance appropriée de l’élément fourni.
Par défaut, aucun mécanisme d’entiercement n’est activé, bien que les administrateurs de serveur puissent le configurer globalement. Il peut également être configuré par programmation via la méthode IDataProtectionBuilder.AddKeyEscrowSink
comme indiqué dans l’exemple ci-dessous. La méthode AddKeyEscrowSink
surcharge miroir les surcharges IServiceCollection.AddSingleton
et IServiceCollection.AddInstance
, car les instances IKeyEscrowSink
sont destinées à être des singletons. Si plusieurs instances IKeyEscrowSink
sont inscrites, chacune d’elles est appelée pendant la génération de clé, de sorte que les clés peuvent être séquestrés simultanément à plusieurs mécanismes.
Il n’existe aucune API pour lire les documents d’une instance IKeyEscrowSink
. Cela est cohérent avec la théorie de conception du mécanisme d’entiercement : il est destiné à rendre le matériel clé accessible à une autorité de confiance, et puisque l’application n’est pas elle-même une autorité de confiance, elle ne doit pas avoir accès à ses propres documents bloqués.
L’exemple de code suivant illustre la création et l’inscription d’un IKeyEscrowSink
où les clés sont séquestrés de telle sorte que seuls les membres de « CONTOSODomain Admins » puissent les récupérer.
Notes
Pour exécuter cet exemple, vous devez être sur un ordinateur Windows 8/Windows Server 2012 joint à un domaine, et le contrôleur de domaine doit être Windows Server 2012 ou version ultérieure.
using System;
using System.IO;
using System.Xml.Linq;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.AspNetCore.DataProtection.XmlEncryption;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
public class Program
{
public static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
.ProtectKeysWithDpapi()
.AddKeyEscrowSink(sp => new MyKeyEscrowSink(sp));
var services = serviceCollection.BuildServiceProvider();
// get a reference to the key manager and force a new key to be generated
Console.WriteLine("Generating new key...");
var keyManager = services.GetService<IKeyManager>();
keyManager.CreateNewKey(
activationDate: DateTimeOffset.Now,
expirationDate: DateTimeOffset.Now.AddDays(7));
}
// A key escrow sink where keys are escrowed such that they
// can be read by members of the CONTOSO\Domain Admins group.
private class MyKeyEscrowSink : IKeyEscrowSink
{
private readonly IXmlEncryptor _escrowEncryptor;
public MyKeyEscrowSink(IServiceProvider services)
{
// Assuming I'm on a machine that's a member of the CONTOSO
// domain, I can use the Domain Admins SID to generate an
// encrypted payload that only they can read. Sample SID from
// https://technet.microsoft.com/library/cc778824(v=ws.10).aspx.
_escrowEncryptor = new DpapiNGXmlEncryptor(
"SID=S-1-5-21-1004336348-1177238915-682003330-512",
DpapiNGProtectionDescriptorFlags.None,
new LoggerFactory());
}
public void Store(Guid keyId, XElement element)
{
// Encrypt the key element to the escrow encryptor.
var encryptedXmlInfo = _escrowEncryptor.Encrypt(element);
// A real implementation would save the escrowed key to a
// write-only file share or some other stable storage, but
// in this sample we'll just write it out to the console.
Console.WriteLine($"Escrowing key {keyId}");
Console.WriteLine(encryptedXmlInfo.EncryptedElement);
// Note: We cannot read the escrowed key material ourselves.
// We need to get a member of CONTOSO\Domain Admins to read
// it for us in the event we need to recover it.
}
}
}
/*
* SAMPLE OUTPUT
*
* Generating new key...
* Escrowing key 38e74534-c1b8-4b43-aea1-79e856a822e5
* <encryptedKey>
* <!-- This key is encrypted with Windows DPAPI-NG. -->
* <!-- Rule: SID=S-1-5-21-1004336348-1177238915-682003330-512 -->
* <value>MIIIfAYJKoZIhvcNAQcDoIIIbTCCCGkCAQ...T5rA4g==</value>
* </encryptedKey>
*/