Erweiterbarkeit der Schlüsselverwaltung in ASP.NET Core

Lesen Sie den Abschnitt "Schlüsselverwaltung" , bevor Sie diesen Abschnitt lesen, da einige der grundlegenden Konzepte dieser APIs erläutert werden.

Warnung: Typen, die eine der folgenden Schnittstellen implementieren, sollten threadsicher für mehrere Anrufer sein.

Schlüssel

Die IKey Schnittstelle ist die grundlegende Darstellung eines Schlüssels in Kryptosystem. Der Begriffsschlüssel wird hier im abstrakten Sinne verwendet, nicht im literalen Sinne des "kryptografischen Schlüsselmaterials". Ein Schlüssel weist die folgenden Eigenschaften auf:

  • Aktivierungs-, Erstellungs- und Ablaufdatum

  • Sperrstatus

  • Schlüsselbezeichner (eine GUID)

Darüber hinaus wird eine Methode verfügbar gemacht, IKey die zum Erstellen einer an diesen Schlüssel gebundenen IAuthenticatedEncryptor-Instanz verwendet werden kann.CreateEncryptor

Darüber hinaus wird eine Methode verfügbar gemacht, IKey die zum Erstellen einer an diesen Schlüssel gebundenen IAuthenticatedEncryptor-Instanz verwendet werden kann.CreateEncryptorInstance

Hinweis

Es gibt keine API zum Abrufen des rohen kryptografischen Materials aus einer IKey Instanz.

IKeyManager

Die IKeyManager Schnittstelle stellt ein Objekt dar, das für allgemeine Schlüsselspeicherung, Abruf und Manipulation verantwortlich ist. Er macht drei Vorgänge auf hoher Ebene verfügbar:

  • Erstellen Sie einen neuen Schlüssel, und speichern Sie ihn im Speicher.

  • Rufen Sie alle Schlüssel aus dem Speicher ab.

  • Widerrufen Sie mindestens einen Schlüssel, und speichern Sie die Sperrinformationen für den Speicher.

Warnung

Das Schreiben einer IKeyManager Aufgabe ist eine sehr erweiterte Aufgabe, und die Mehrheit der Entwickler sollte es nicht versuchen. Stattdessen sollten die meisten Entwickler die von der XmlKeyManager-Klasse angebotenen Einrichtungen nutzen.

XmlKeyManager

Der XmlKeyManager Typ ist die in-box konkrete Implementierung von IKeyManager. Es bietet mehrere nützliche Einrichtungen, einschließlich Schlüssel-Escrow- und Verschlüsselung von Schlüsseln im Ruhezustand. Schlüssel in diesem System werden als XML-Elemente (insbesondere XElement) dargestellt.

XmlKeyManager hängt von mehreren anderen Komponenten im Laufe der Erfüllung seiner Aufgaben ab:

  • AlgorithmConfiguration, die die algorithmen diktieren, die von neuen Schlüsseln verwendet werden.

  • IXmlRepository, die steuert, wo Schlüssel im Speicher beibehalten werden.

  • IXmlEncryptor [optional], wodurch die Verschlüsselung von Schlüsseln im Ruhezustand möglich ist.

  • IKeyEscrowSink [optional], das wichtige Escrow-Dienste bereitstellt.

  • IXmlRepository, die steuert, wo Schlüssel im Speicher beibehalten werden.

  • IXmlEncryptor [optional], wodurch die Verschlüsselung von Schlüsseln im Ruhezustand möglich ist.

  • IKeyEscrowSink [optional], das wichtige Escrow-Dienste bereitstellt.

Nachfolgend finden Sie Diagramme mit hoher Ebene, die angeben, wie diese Komponenten miteinander XmlKeyManagerverkabelt werden.

Schlüsselerstellung

Schlüsselerstellung / CreateNewKey

In der Implementierung von CreateNewKey, wird die AlgorithmConfiguration Komponente verwendet, um eine eindeutige IAuthenticatedEncryptorDescriptor, die dann als XML serialisiert wird. Wenn ein Schlüssel-Escrow-Sink vorhanden ist, wird der unformatierte (unverschlüsselte) XML-Code für die Spüle für den langfristigen Speicher bereitgestellt. Der unverschlüsselte XML-Code wird dann über ein IXmlEncryptor (sofern erforderlich) ausgeführt, um das verschlüsselte XML-Dokument zu generieren. Dieses verschlüsselte Dokument wird über die IXmlRepository. (Wenn keine IXmlEncryptor Konfiguration erfolgt, wird das unverschlüsselte Dokument in der IXmlRepository.)

Schlüsselabruf

Schlüsselerstellung

Schlüsselerstellung / CreateNewKey

In der Implementierung von CreateNewKey, wird die IAuthenticatedEncryptorConfiguration Komponente verwendet, um eine eindeutige IAuthenticatedEncryptorDescriptor, die dann als XML serialisiert wird. Wenn ein Schlüssel-Escrow-Sink vorhanden ist, wird der unformatierte (unverschlüsselte) XML-Code für die Spüle für den langfristigen Speicher bereitgestellt. Der unverschlüsselte XML-Code wird dann über ein IXmlEncryptor (sofern erforderlich) ausgeführt, um das verschlüsselte XML-Dokument zu generieren. Dieses verschlüsselte Dokument wird über die IXmlRepository. (Wenn keine IXmlEncryptor Konfiguration erfolgt, wird das unverschlüsselte Dokument in der IXmlRepository.)

Schlüsselabruf

Schlüsselabruf / GetAllKeys

In der Implementierung von GetAllKeys, werden die XML-Dokumente, die Schlüssel und Sperrungen darstellen, aus dem zugrunde liegenden IXmlRepositorygelesen. Wenn diese Dokumente verschlüsselt sind, entschlüsselt das System diese automatisch. XmlKeyManager erstellt die entsprechenden IAuthenticatedEncryptorDescriptorDeserializer Instanzen, um die Dokumente wieder in IAuthenticatedEncryptorDescriptor Instanzen zu deserialisieren, die dann in einzelne IKey Instanzen umgebrochen werden. Diese Auflistung von IKey Instanzen wird an den Aufrufer zurückgegeben.

Weitere Informationen zu den bestimmten XML-Elementen finden Sie im Schlüsselspeicherformatdokument.

IXmlRepository

Die IXmlRepository Schnittstelle stellt einen Typ dar, der XML in einem Sicherungsspeicher beibehalten und XML abrufen kann. Es macht zwei APIs verfügbar:

  • GetAllElements :IReadOnlyCollection<XElement>

  • StoreElement(XElement element, string friendlyName)

Implementierungen von IXmlRepository Daten müssen die XML-Daten nicht analysieren, die sie durchlaufen. Sie sollten die XML-Dokumente als undurchsichtig behandeln und höhere Ebenen bedenken lassen, dass die Dokumente generiert und analysiert werden.

Es gibt vier integrierte Betontypen, die Folgendes implementieren IXmlRepository:

Weitere Informationen finden Sie im Dokument der wichtigsten Speicheranbieter .

Das Registrieren einer benutzerdefinierten Anwendung IXmlRepository ist bei Verwendung eines anderen Sicherungsspeichers geeignet (z. B. Azure Table Storage).

Registrieren Sie eine benutzerdefinierte Instanz, um das standardmäßige IXmlRepository Repository anwendungsweit zu ändern:

services.Configure<KeyManagementOptions>(options => options.XmlRepository = new MyCustomXmlRepository());
services.AddSingleton<IXmlRepository>(new MyCustomXmlRepository());

IXmlEncryptor

Die IXmlEncryptor Schnittstelle stellt einen Typ dar, der ein NUR-Text-XML-Element verschlüsseln kann. Es macht eine einzelne API verfügbar:

  • Encrypt(XElement plaintextElement) : EncryptedXmlInfo

Wenn eine serialisierte IAuthenticatedEncryptorDescriptor Elemente enthält, die als "Verschlüsselung erforderlich" gekennzeichnet sind, XmlKeyManager führen Sie diese Elemente über die konfigurierte IXmlEncryptorMethode aus, und es wird das encipherierte Element anstelle des Nurtextelements Encrypt auf dem IXmlRepository. Die Ausgabe der Encrypt Methode ist ein EncryptedXmlInfo Objekt. Dieses Objekt ist ein Wrapper, der sowohl die resultierende enciphered XElement als auch den Typ enthält, der ein IXmlDecryptor Objekt darstellt, das verwendet werden kann, um das entsprechende Element zu entschlüsseln.

Es gibt vier integrierte Betontypen, die Folgendes implementieren IXmlEncryptor:

Weitere Informationen finden Sie in der Schlüsselverschlüsselung im Restdokument .

Registrieren Sie eine benutzerdefinierte Instanz, um den standardmäßigen Schlüsselverschlüsselungs-at-Rest-Mechanismus anwendungsweit IXmlEncryptor zu ändern:

services.Configure<KeyManagementOptions>(options => options.XmlEncryptor = new MyCustomXmlEncryptor());
services.AddSingleton<IXmlEncryptor>(new MyCustomXmlEncryptor());

IXmlDecryptor

Die IXmlDecryptor Schnittstelle stellt einen Typ dar, der weiß, wie eine XElement entschlüsselte, die über eine IXmlEncryptorEntschlüsselung enciphered wurde. Es macht eine einzelne API verfügbar:

  • Decrypt(XElement encryptedElement) : XElement

Die Decrypt Methode rückgängigmachen die verschlüsselung, die von IXmlEncryptor.Encrypt. Im Allgemeinen wird jede konkrete IXmlEncryptor Umsetzung eine entsprechende konkrete IXmlDecryptor Umsetzung haben.

Typen, die implementieren IXmlDecryptor , sollten über einen der folgenden beiden öffentlichen Konstruktoren verfügen:

  • .ctor(IServiceProvider)
  • .ctor()

Hinweis

Der IServiceProvider an den Konstruktor übergebene Wert kann null sein.

IKeyEscrowSink

Die IKeyEscrowSink Schnittstelle stellt einen Typ dar, der einen Fehler bei vertraulichen Informationen ausführen kann. Erinnern Sie sich daran, dass serialisierte Deskriptoren vertrauliche Informationen (z. B. kryptografisches Material) enthalten können, und dies ist dies die Einführung des IXmlEncryptor-Typs an erster Stelle. Unfälle treten jedoch auf, und Schlüsselringe können gelöscht oder beschädigt werden.

Die Escrow-Schnittstelle bietet eine Notfall-Escape-Kupplung, die den Zugriff auf die unformatierte serialisierte XML-Datei ermöglicht, bevor sie von jedem konfigurierten IXmlEncryptor transformiert wird. Die Schnittstelle macht eine einzelne API verfügbar:

  • Store(Guid keyId, XElement-Element)

Es ist bis zur Implementierung erforderlich, um das bereitgestellte Element auf sichere Weise in Übereinstimmung mit der IKeyEscrowSink Geschäftsrichtlinie zu behandeln. Eine mögliche Implementierung könnte für das Escrow-Sink sein, um das XML-Element mithilfe eines bekannten Unternehmens-X.509-Zertifikats zu verschlüsseln, bei dem der private Schlüssel des Zertifikats escrowed wurde; Der CertificateXmlEncryptor Typ kann dies unterstützen. Die IKeyEscrowSink Implementierung ist auch dafür verantwortlich, das bereitgestellte Element entsprechend beizubehalten.

Standardmäßig ist kein Escrow-Mechanismus aktiviert, obwohl Serveradministratoren diese global konfigurieren können. Sie kann auch programmgesteuert über die IDataProtectionBuilder.AddKeyEscrowSink Methode konfiguriert werden, wie im folgenden Beispiel dargestellt. Die AddKeyEscrowSink Methodenüberladungen spiegeln die IServiceCollection.AddSingleton und IServiceCollection.AddInstance überladungen, da IKeyEscrowSink Instanzen singletons sein sollen. Wenn mehrere IKeyEscrowSink Instanzen registriert sind, wird jeder während der Schlüsselgenerierung aufgerufen, sodass Schlüssel gleichzeitig auf mehrere Mechanismen verteilt werden können.

Es gibt keine API zum Lesen von Material aus einer IKeyEscrowSink Instanz. Dies ist im Einklang mit der Entwurfstheorie des Escrow-Mechanismus: Es soll das schlüsselmaterial für eine vertrauenswürdige Behörde zugänglich machen, und da die Anwendung selbst keine vertrauenswürdige Behörde ist, sollte sie keinen Zugriff auf ihr eigenes verrowtes Material haben.

Im folgenden Beispielcode wird das Erstellen und Registrieren eines IKeyEscrowSink Schlüssels veranschaulicht, sodass nur Mitglieder von "CONTOSODomain Admins" sie wiederherstellen können.

Hinweis

Um dieses Beispiel auszuführen, müssen Sie sich auf einem domänenbezogenen Windows 8/Windows Server 2012 Computer befinden, und der Domänencontroller muss Windows Server 2012 oder höher sein.

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>
 */