Estendibilità della gestione delle chiavi in ASP.NET Core
Leggere la sezione relativa alla gestione delle chiavi prima di leggere questa sezione, come illustra alcuni dei concetti fondamentali alla base di queste API.
Avviso: i tipi che implementano una delle interfacce seguenti devono essere thread-safe per più chiamanti.
Chiave
L'interfaccia IKey
è la rappresentazione di base di una chiave nel sistema di crittografia. Il termine chiave viene usato qui nel senso astratto, non nel senso letterale del "materiale della chiave crittografica". Una chiave ha le proprietà seguenti:
Date di attivazione, creazione e scadenza
Stato di revoca
Identificatore di chiave (GUID)
Espone inoltre IKey
un CreateEncryptor
metodo che può essere usato per creare un'istanza IAuthenticatedEncryptor associata a questa chiave.
Espone inoltre IKey
un CreateEncryptorInstance
metodo che può essere usato per creare un'istanza IAuthenticatedEncryptor associata a questa chiave.
Nota
Non esiste alcuna API per recuperare il materiale crittografico non elaborato da un'istanza IKey
di .
IKeyManager
L'interfaccia IKeyManager
rappresenta un oggetto responsabile dell'archiviazione generale delle chiavi, del recupero e della manipolazione. Espone tre operazioni generali:
Creare una nuova chiave e renderla persistente nell'archiviazione.
Ottenere tutte le chiavi dall'archiviazione.
Revocare una o più chiavi e rendere persistenti le informazioni di revoca nell'archiviazione.
Avviso
La scrittura di un è un'attività IKeyManager
molto avanzata e la maggior parte degli sviluppatori non dovrebbe provarla. La maggior parte degli sviluppatori dovrebbe invece sfruttare le funzionalità offerte dalla classe XmlKeyManager .
XmlKeyManager
Il XmlKeyManager
tipo è l'implementazione concreta in scatola di IKeyManager
. Offre diverse funzionalità utili, tra cui deposito delle chiavi e crittografia delle chiavi in rest. Le chiavi in questo sistema sono rappresentate come elementi XML (in particolare XElement).
XmlKeyManager
dipende da diversi altri componenti nel corso del completamento delle attività:
AlgorithmConfiguration
, che determina gli algoritmi usati dalle nuove chiavi.IXmlRepository
, che controlla dove le chiavi vengono mantenute nell'archiviazione.IXmlEncryptor
[facoltativo], che consente la crittografia delle chiavi in rest.IKeyEscrowSink
[facoltativo], che fornisce servizi di deposito chiavi.
IXmlRepository
, che controlla dove le chiavi vengono mantenute nell'archiviazione.IXmlEncryptor
[facoltativo], che consente la crittografia delle chiavi in rest.IKeyEscrowSink
[facoltativo], che fornisce servizi di deposito chiavi.
Di seguito sono riportati diagrammi di alto livello che indicano come questi componenti vengono collegati insieme all'interno XmlKeyManager
di .
Creazione della chiave/CreateNewKey
Nell'implementazione di CreateNewKey
, il AlgorithmConfiguration
componente viene usato per creare un oggetto univoco IAuthenticatedEncryptorDescriptor
, che viene quindi serializzato come XML. Se è presente un sink di deposito delle chiavi, il codice XML non elaborato (non crittografato) viene fornito al sink per l'archiviazione a lungo termine. Il codice XML non crittografato viene quindi eseguito tramite un IXmlEncryptor
oggetto (se necessario) per generare il documento XML crittografato. Questo documento crittografato viene salvato in modo permanente nell'archiviazione IXmlRepository
a lungo termine tramite . Se non IXmlEncryptor
è configurato, il documento non crittografato viene salvato in modo permanente in IXmlRepository
.
Creazione della chiave/CreateNewKey
Nell'implementazione di CreateNewKey
, il IAuthenticatedEncryptorConfiguration
componente viene usato per creare un oggetto univoco IAuthenticatedEncryptorDescriptor
, che viene quindi serializzato come XML. Se è presente un sink di deposito delle chiavi, il codice XML non elaborato (non crittografato) viene fornito al sink per l'archiviazione a lungo termine. Il codice XML non crittografato viene quindi eseguito tramite un IXmlEncryptor
oggetto (se necessario) per generare il documento XML crittografato. Questo documento crittografato viene salvato in modo permanente nell'archiviazione IXmlRepository
a lungo termine tramite . Se non IXmlEncryptor
è configurato, il documento non crittografato viene salvato in modo permanente in IXmlRepository
.
Recupero chiavi/GetAllKeys
Nell'implementazione di GetAllKeys
, i documenti XML che rappresentano chiavi e revoche vengono letti dall'oggetto sottostante IXmlRepository
. Se questi documenti sono crittografati, il sistema li decrittograferà automaticamente. XmlKeyManager
crea le istanze appropriate IAuthenticatedEncryptorDescriptorDeserializer
per deserializzare nuovamente i documenti in IAuthenticatedEncryptorDescriptor
istanze di , che vengono quindi racchiuse in singole IKey
istanze. Questa raccolta di IKey
istanze viene restituita al chiamante.
Altre informazioni sugli elementi XML specifici sono disponibili nel documento relativo al formato di archiviazione delle chiavi.
IXmlRepository
L'interfaccia IXmlRepository
rappresenta un tipo che può rendere persistente xml in e recuperare XML da un archivio di backup. Espone due API:
GetAllElements
:IReadOnlyCollection<XElement>
StoreElement(XElement element, string friendlyName)
Le implementazioni di IXmlRepository
non devono analizzare il codice XML passandole. Devono trattare i documenti XML come opachi e consentire ai livelli più elevati di generare e analizzare i documenti.
Esistono quattro tipi di cemento incorporati che implementano IXmlRepository
:
Per altre informazioni, vedere il documento relativo ai provider di archiviazione delle chiavi.
La registrazione di un oggetto personalizzato IXmlRepository
è appropriata quando si usa un archivio di backup diverso, ad esempio Archiviazione tabelle di Azure.
Per modificare il repository predefinito a livello di applicazione, registrare un'istanza personalizzata IXmlRepository
:
services.Configure<KeyManagementOptions>(options => options.XmlRepository = new MyCustomXmlRepository());
services.AddSingleton<IXmlRepository>(new MyCustomXmlRepository());
IXmlEncryptor
L'interfaccia IXmlEncryptor
rappresenta un tipo in grado di crittografare un elemento XML di testo non crittografato. Espone una singola API:
- Encrypt(XElement plaintextElement): EncryptedXmlInfo
Se un oggetto serializzato IAuthenticatedEncryptorDescriptor
contiene elementi contrassegnati come "richiede la crittografia", XmlKeyManager
eseguirà tali elementi tramite il metodo configurato IXmlEncryptor
Encrypt
e manterrà l'elemento crittografato anziché l'elemento di testo non crittografato nell'oggetto IXmlRepository
. L'output del Encrypt
metodo è un EncryptedXmlInfo
oggetto . Questo oggetto è un wrapper che contiene sia l'encifratto XElement
risultante che il type che rappresenta un IXmlDecryptor
oggetto che può essere utilizzato per decifrare l'elemento corrispondente.
Esistono quattro tipi di cemento incorporati che implementano IXmlEncryptor
:
Per altre informazioni, vedere la crittografia della chiave nel rest documento .
Per modificare il meccanismo di crittografia della chiave predefinito arest livello di applicazione, registrare un'istanza personalizzata IXmlEncryptor
:
services.Configure<KeyManagementOptions>(options => options.XmlEncryptor = new MyCustomXmlEncryptor());
services.AddSingleton<IXmlEncryptor>(new MyCustomXmlEncryptor());
IXmlDecryptor
L'interfaccia IXmlDecryptor
rappresenta un tipo che sa come decrittografare un oggetto XElement
che è stato crittografato tramite un oggetto IXmlEncryptor
. Espone una singola API:
- Decrypt(XElement encryptedElement): XElement
Il Decrypt
metodo annulla la crittografia eseguita da IXmlEncryptor.Encrypt
. In genere, ogni implementazione concreta IXmlEncryptor
avrà un'implementazione concreta IXmlDecryptor
corrispondente.
I tipi che implementano IXmlDecryptor
devono avere uno dei due costruttori pubblici seguenti:
- .ctor(IServiceProvider)
- .ctor()
Nota
L'oggetto IServiceProvider
passato al costruttore può essere Null.
IKeyEscrowSink
L'interfaccia IKeyEscrowSink
rappresenta un tipo che può eseguire il deposito di informazioni riservate. Tenere presente che i descrittori serializzati possono contenere informazioni riservate (ad esempio materiale crittografico) e questo è ciò che ha portato all'introduzione del tipo IXmlEncryptor in primo luogo. Tuttavia, si verificano incidenti e gli anelli chiave possono essere eliminati o danneggiati.
L'interfaccia di deposito fornisce un tratteggio di escape di emergenza, consentendo l'accesso al codice XML serializzato non elaborato prima che venga trasformato da qualsiasi IXmlEncryptor configurato. L'interfaccia espone una singola API:
- Store(Guid keyId, elemento XElement)
Spetta all'implementazione IKeyEscrowSink
gestire l'elemento fornito in modo sicuro con i criteri aziendali. Una possibile implementazione potrebbe essere per il sink di deposito per crittografare l'elemento XML usando un certificato X.509 aziendale noto in cui è stata depositata la chiave privata del certificato; il CertificateXmlEncryptor
tipo può essere utile per questo. L'implementazione IKeyEscrowSink
è anche responsabile della persistenza dell'elemento fornito in modo appropriato.
Per impostazione predefinita, non è abilitato alcun meccanismo di deposito, anche se gli amministratori del server possono configurarlo a livello globale. Può anche essere configurato a livello di codice tramite il IDataProtectionBuilder.AddKeyEscrowSink
metodo come illustrato nell'esempio seguente. L'overload del AddKeyEscrowSink
metodo esegue il mirroring degli IServiceCollection.AddSingleton
overload e IServiceCollection.AddInstance
, poiché IKeyEscrowSink
le istanze devono essere singleton. Se vengono registrate più IKeyEscrowSink
istanze, ognuna verrà chiamata durante la generazione di chiavi, in modo che le chiavi possano essere depositate in più meccanismi contemporaneamente.
Non esiste alcuna API per leggere materiale da un'istanza IKeyEscrowSink
. Ciò è coerente con la teoria di progettazione del meccanismo di deposito: è progettato per rendere il materiale chiave accessibile a un'autorità attendibile e poiché l'applicazione non è un'autorità attendibile, non dovrebbe avere accesso al proprio materiale deposito.
Il codice di esempio seguente illustra la creazione e la registrazione di una IKeyEscrowSink
posizione in cui vengono depositate le chiavi in modo che solo i membri di "CONTOSODomain Admins" possano recuperarli.
Nota
Per eseguire questo esempio, è necessario trovarsi in un computer Windows 8/Windows Server 2012 aggiunto a un dominio e il controller di dominio deve essere Windows Server 2012 o versione successiva.
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>
*/