Sdílet prostřednictvím


Rozšiřitelnost správy klíčů v ASP.NET Core

Před čtením této části si přečtěte část správy klíčů, protože vysvětluje některé základní koncepty těchto rozhraní API.

Upozornění: Typy, které implementují některá z následujících rozhraní, by měly být pro více volajících bezpečné pro více volajících.

Klíč

Rozhraní IKey je základní reprezentace klíče v kryptografickém systému. Klíč termínu se zde používá v abstraktním smyslu, ne v literálovém smyslu "kryptografický klíč materiálu". Klíč má následující vlastnosti:

  • Data aktivace, vytváření a vypršení platnosti

  • Stav odvolání

  • Identifikátor klíče (identifikátor GUID)

Kromě toho zveřejňuje metoduCreateEncryptor, IKey která se dá použít k vytvoření instance IAuthenticatedEncryptor svázané s tímto klíčem.

Kromě toho zveřejňuje metoduCreateEncryptorInstance, IKey která se dá použít k vytvoření instance IAuthenticatedEncryptor svázané s tímto klíčem.

Poznámka

Z instance neexistuje žádné rozhraní API k načtení nezpracovaného IKey kryptografického materiálu.

IKeyManager

Rozhraní IKeyManager představuje objekt zodpovědný za obecné úložiště klíčů, načítání a manipulaci. Zpřístupňuje tři operace vysoké úrovně:

  • Vytvořte nový klíč a uložte ho do úložiště.

  • Získejte všechny klíče z úložiště.

  • Odvolejte jeden nebo více klíčů a uchováte informace o odvolání do úložiště.

Upozorňující

Psaní je IKeyManager velmi pokročilý úkol a většina vývojářů by se o to neměla pokoušet. Místo toho by většina vývojářů měla využívat možnosti nabízené třídou XmlKeyManager .

XmlKeyManager

Typ XmlKeyManager je in-box beton implementace IKeyManager. Poskytuje několik užitečných zařízení, včetně úschovy klíčů a šifrování neaktivních uložených klíčů. Klíče v tomto systému jsou reprezentovány jako elementy XML (konkrétně XElement).

XmlKeyManager závisí na několika dalších komponentách v průběhu plnění svých úkolů:

  • AlgorithmConfiguration, který určuje algoritmy používané novými klíči.

  • IXmlRepository– určuje, kde se klíče uchovávají v úložišti.

  • IXmlEncryptor [volitelné], což umožňuje šifrování neaktivních uložených klíčů.

  • IKeyEscrowSink [volitelné], které poskytuje služby pro úschovu klíčů.

  • IXmlRepository– určuje, kde se klíče uchovávají v úložišti.

  • IXmlEncryptor [volitelné], což umožňuje šifrování neaktivních uložených klíčů.

  • IKeyEscrowSink [volitelné], které poskytuje služby pro úschovu klíčů.

Níže jsou uvedeny diagramy vysoké úrovně, které ukazují, jak jsou tyto komponenty propojeny v rámci XmlKeyManager.

Key Creation

Vytvoření klíče / CreateNewKey

Při implementaci CreateNewKeyse komponenta AlgorithmConfiguration používá k vytvoření jedinečného IAuthenticatedEncryptorDescriptor, který se pak serializuje jako XML. Pokud je k dispozici jímka pro escrow klíče, nezpracovaný (nešifrovaný) XML je k dispozici jímce pro dlouhodobé úložiště. Nešifrovaný XML se pak spustí prostřednictvím IXmlEncryptor (pokud je to nutné) pro vygenerování šifrovaného dokumentu XML. Tento šifrovaný dokument je trvale uložen do dlouhodobého úložiště prostřednictvím IXmlRepository. (Pokud není nakonfigurovaný žádný IXmlEncryptor , nezašifrovaný dokument se zachovají v souboru IXmlRepository.)

Key Retrieval

Key Creation

Vytvoření klíče / CreateNewKey

Při implementaci CreateNewKeyse komponenta IAuthenticatedEncryptorConfiguration používá k vytvoření jedinečného IAuthenticatedEncryptorDescriptor, který se pak serializuje jako XML. Pokud je k dispozici jímka pro escrow klíče, nezpracovaný (nešifrovaný) XML je k dispozici jímce pro dlouhodobé úložiště. Nešifrovaný XML se pak spustí prostřednictvím IXmlEncryptor (pokud je to nutné) pro vygenerování šifrovaného dokumentu XML. Tento šifrovaný dokument je trvale uložen do dlouhodobého úložiště prostřednictvím IXmlRepository. (Pokud není nakonfigurovaný žádný IXmlEncryptor , nezašifrovaný dokument se zachovají v souboru IXmlRepository.)

Key Retrieval

Načítání klíčů / GetAllKeys

Při implementaci GetAllKeysjsou dokumenty XML představující klíče a odvolání načteny z podkladového IXmlRepositorysouboru . Pokud jsou tyto dokumenty šifrované, systém je automaticky dešifruje. XmlKeyManager vytvoří příslušné IAuthenticatedEncryptorDescriptorDeserializer instance pro deserializaci dokumentů zpět do IAuthenticatedEncryptorDescriptor instancí, které jsou pak zabaleny do jednotlivých IKey instancí. Tato kolekce IKey instancí se vrátí volajícímu.

Další informace o konkrétních elementech XML najdete v dokumentu formátu úložiště klíčů.

IXmlRepository

Rozhraní IXmlRepository představuje typ, který může zachovat XML do a načíst XML z záložního úložiště. Zpřístupňuje dvě rozhraní API:

  • GetAllElements :IReadOnlyCollection<XElement>

  • StoreElement(XElement element, string friendlyName)

IXmlRepository Implementace nemusí parsovat kód XML, který je předává. S dokumenty XML by měli zacházet jako s neprůhlenou a nechat vyšší vrstvy obavy, že dokumenty vygenerují a parsují.

Existují čtyři předdefinované typy betonů, které implementují IXmlRepository:

Další informace najdete v dokumentu poskytovatelé úložiště klíčů.

Registrace vlastního IXmlRepository úložiště je vhodná při použití jiného záložního úložiště (například Azure Table Storage).

Pokud chcete změnit výchozí aplikaci úložiště, zaregistrujte vlastní IXmlRepository instanci:

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

IXmlEncryptor

Rozhraní IXmlEncryptor představuje typ, který může šifrovat element XML ve formátu prostého textu. Zpřístupňuje jedno rozhraní API:

  • Encrypt(XElement plaintextElement) : EncryptedXmlInfo

Pokud serializovaný IAuthenticatedEncryptorDescriptor obsahuje všechny prvky označené jako "vyžaduje šifrování", pak XmlKeyManager tyto prvky spustí prostřednictvím konfigurované IXmlEncryptormetody 's Encrypt , a zachová šifrovaný element místo elementu prostého textu do IXmlRepository. Výstupem Encrypt metody je EncryptedXmlInfo objekt. Tento objekt je obálka, která obsahuje výslednou šifru XElement i typ, který představuje IXmlDecryptor , který lze použít k dešifru odpovídajícího prvku.

Existují čtyři předdefinované typy betonů, které implementují IXmlEncryptor:

Další informace najdete v dokumentu šifrování neaktivních uložených klíčů.

Pokud chcete změnit výchozí mechanismus šifrování neaktivních uložených klíčů, zaregistrujte vlastní IXmlEncryptor instanci:

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

IXmlDecryptor

Rozhraní IXmlDecryptor představuje typ, který ví, jak dešifrovat XElement , který byl šifrován prostřednictvím IXmlEncryptor. Zpřístupňuje jedno rozhraní API:

  • Decrypt(XElement encryptedElement) : XElement

Metoda Decrypt vrátí zpět šifrování provedené .IXmlEncryptor.Encrypt Obecně platí, že každá konkrétní IXmlEncryptor implementace bude mít odpovídající konkrétní IXmlDecryptor implementaci.

Typy, které implementují IXmlDecryptor , by měly mít jeden z následujících dvou veřejných konstruktorů:

  • .ctor(IServiceProvider)
  • .ctor()

Poznámka

Předání IServiceProvider konstruktoru může mít hodnotu null.

IKeyEscrowSink

Rozhraní IKeyEscrowSink představuje typ, který může provádět escrow citlivých informací. Vzpomeňte si, že serializované popisovače můžou obsahovat citlivé informace (například kryptografický materiál), a to je to, co vedlo k zavedení typu IXmlEncryptor na prvním místě. Dojde ale k nehodám a klíče se dají odstranit nebo poškodit.

Rozhraní escrow poskytuje nouzový únikový šraf, který umožňuje přístup k nezpracované serializované XML předtím, než je transformován všemi nakonfigurovanými IXmlEncryptor. Rozhraní zveřejňuje jedno rozhraní API:

  • Store(Guid keyId, element XElement)

Je na implementaci IKeyEscrowSink , aby zvládla poskytnutý prvek zabezpečeným způsobem konzistentním s obchodními zásadami. Jednou z možných implementací může být, aby jímka escrow zašifrovala element XML pomocí známého podnikového certifikátu X.509, kde je privátní klíč certifikátu escrowed; tento CertificateXmlEncryptor typ vám může pomoct. Implementace IKeyEscrowSink je také zodpovědná za zachování poskytnutého prvku odpovídajícím způsobem.

Ve výchozím nastavení není povolen žádný mechanismus escrow, ale správci serveru můžou tento mechanismus nakonfigurovat globálně. Dá se také nakonfigurovat programově prostřednictvím IDataProtectionBuilder.AddKeyEscrowSink metody, jak je znázorněno v ukázce níže. Metoda AddKeyEscrowSink přetěžuje zrcadlení IServiceCollection.AddSingleton a IServiceCollection.AddInstance přetížení, protože IKeyEscrowSink instance mají být singletony. Pokud je zaregistrovaných více IKeyEscrowSink instancí, bude každý z nich volána během generování klíčů, takže klíče je možné současně vysunout do několika mechanismů.

Z instance neexistuje žádné rozhraní API ke čtení materiálu IKeyEscrowSink . To je konzistentní s teorii návrhu mechanismu escrow: je určeno, aby byl klíčový materiál přístupný důvěryhodné autoritě, a vzhledem k tomu, že aplikace není důvěryhodnou autoritou, neměla by mít přístup k vlastnímu escrowed materiálu.

Následující ukázkový kód ukazuje vytvoření a registraci IKeyEscrowSink klíče, kde jsou klíče escrowd, aby je mohli obnovit pouze členové "CONTOSODomain Správa s".

Poznámka

Abyste mohli tuto ukázku spustit, musíte být na počítači s Windows 8 nebo Windows Serverem 2012 připojeným k doméně a řadič domény musí být Windows Server 2012 nebo novější.

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