Share via


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 inattive. 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 inattive.

  • 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 inattive.

  • 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 XmlKeyManagerdi .

Key Creation

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 IXmlRepositorya lungo termine tramite . Se non IXmlEncryptor è configurato, il documento non crittografato viene salvato in modo permanente in IXmlRepository.

Key Retrieval

Key Creation

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 IXmlRepositorya lungo termine tramite . Se non IXmlEncryptor è configurato, il documento non crittografato viene salvato in modo permanente in IXmlRepository.

Key Retrieval

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, tabella di Azure Archiviazione).

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 IXmlEncryptorEncrypt 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 il documento relativo alla crittografia delle chiavi inattivi.

Per modificare l'applicazione predefinita key-encryption-at-rest, 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 un oggetto IKeyEscrowSink in cui vengono depositate le chiavi in modo che solo i membri di "CONTOSODomain Amministrazione s" 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>
 */