Расширяемость управления ключами в ASP.NET Core

Ознакомьтесь с разделом управления ключами перед чтением этого раздела, так как он объясняет некоторые основные понятия, лежащие в основе этих API.

Предупреждение. Типы, реализующие любой из следующих интерфейсов, должны быть потокобезопасны для нескольких вызывающих.

Ключ

Интерфейс IKey — это базовое представление ключа в криптосистеме. Ключ термина используется здесь в абстрактном смысле, а не в буквальном смысле "материал криптографического ключа". Ключ имеет следующие свойства:

  • Даты активации, создания и окончания срока действия

  • Состояние отзыва.

  • Идентификатор ключа (GUID)

Кроме того, IKey предоставляет CreateEncryptor метод, который можно использовать для создания экземпляра IAuthenticatedEncryptor, привязанного к этому ключу.

Кроме того, IKey предоставляет CreateEncryptorInstance метод, который можно использовать для создания экземпляра IAuthenticatedEncryptor, привязанного к этому ключу.

Примечание.

Нет API для получения необработанного криптографического материала из экземпляра IKey .

IKeyManager

Интерфейс IKeyManager представляет объект, отвечающий за общее хранилище ключей, извлечение и манипуляцию. Он предоставляет три высокоуровневые операции:

  • Создайте новый ключ и сохраните его в хранилище.

  • Получение всех ключей из хранилища.

  • Отмените один или несколько ключей и сохраните сведения о отзывах в хранилище.

Предупреждение

IKeyManager Написание является очень сложной задачей, и большинство разработчиков не должны пытаться его. Вместо этого большинство разработчиков должны воспользоваться объектами, предлагаемыми классом XmlKeyManager .

XmlKeyManager

Тип XmlKeyManager — это встроенная конкретная реализация IKeyManager. Он предоставляет несколько полезных средств, включая депонирования ключей и шифрование неактивных ключей. Ключи в этой системе представлены как XML-элементы (в частности, XElement).

XmlKeyManager зависит от нескольких других компонентов в ходе выполнения своих задач:

  • AlgorithmConfiguration, который диктует алгоритмы, используемые новыми ключами.

  • IXmlRepository, который определяет, где ключи сохраняются в хранилище.

  • IXmlEncryptor [необязательно], который позволяет шифровать неактивные ключи.

  • IKeyEscrowSink [необязательно], предоставляющий службы депонирования ключей.

  • IXmlRepository, который определяет, где ключи сохраняются в хранилище.

  • IXmlEncryptor [необязательно], который позволяет шифровать неактивные ключи.

  • IKeyEscrowSink [необязательно], предоставляющий службы депонирования ключей.

Ниже приведены высокоуровневые схемы, указывающие, как эти компоненты связаны между XmlKeyManagerсобой.

Key Creation

Создание ключа / CreateNewKey

В реализации компонент используется для создания уникального CreateNewKeyAlgorithmConfigurationIAuthenticatedEncryptorDescriptorкомпонента, который затем сериализуется как XML. Если приемник депонирования ключа присутствует, необработанный (незашифрованный) XML предоставляется приемнику для долгосрочного хранения. Затем незашифрованный XML выполняется через IXmlEncryptor (при необходимости) для создания зашифрованного XML-документа. Этот зашифрованный документ сохраняется в долгосрочном хранилище через хранилище IXmlRepository. (Если не IXmlEncryptor настроено, незашифрованный документ сохраняется в IXmlRepository.)

Key Retrieval

Key Creation

Создание ключа / CreateNewKey

В реализации компонент используется для создания уникального CreateNewKeyIAuthenticatedEncryptorConfigurationIAuthenticatedEncryptorDescriptorкомпонента, который затем сериализуется как XML. Если приемник депонирования ключа присутствует, необработанный (незашифрованный) XML предоставляется приемнику для долгосрочного хранения. Затем незашифрованный XML выполняется через IXmlEncryptor (при необходимости) для создания зашифрованного XML-документа. Этот зашифрованный документ сохраняется в долгосрочном хранилище через хранилище IXmlRepository. (Если не IXmlEncryptor настроено, незашифрованный документ сохраняется в IXmlRepository.)

Key Retrieval

Извлечение ключей / GetAllKeys

В реализации GetAllKeysXML-документы, представляющие ключи и отзыва, считываются из базового IXmlRepository. Если эти документы шифруются, система автоматически расшифровывает их. XmlKeyManager создает соответствующие IAuthenticatedEncryptorDescriptorDeserializer экземпляры для десериализации документов обратно в IAuthenticatedEncryptorDescriptor экземпляры, которые затем упаковываются в отдельные IKey экземпляры. Эта коллекция экземпляров IKey возвращается вызывающей объекту.

Дополнительные сведения о конкретных XML-элементах можно найти в документе формата хранилища ключей.

IXmlRepository

Интерфейс IXmlRepository представляет тип, который может сохранять XML и извлекать XML из резервного хранилища. Он предоставляет два API:

  • GetAllElements :IReadOnlyCollection<XElement>

  • StoreElement(XElement element, string friendlyName)

IXmlRepository Реализации не нужно анализировать XML-код, проходящий через них. Они должны рассматривать XML-документы как непрозрачные и позволяют более высоким слоям беспокоиться о создании и анализе документов.

Существует четыре встроенных конкретных типа, реализующих IXmlRepository:

Дополнительные сведения см. в документе поставщиков хранилища ключей.

Регистрация настраиваемого объекта IXmlRepository подходит при использовании другого резервного хранилища (например, таблицы Azure служба хранилища).

Чтобы изменить приложение репозитория по умолчанию, зарегистрируйте пользовательский IXmlRepository экземпляр:

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

IXmlEncryptor

Интерфейс IXmlEncryptor представляет тип, который может шифровать xml-элемент обычного текста. Он предоставляет один API:

  • Encrypt(XElement plaintextElement) : EncryptedXmlInfo

Если сериализованный IAuthenticatedEncryptorDescriptor содержит все элементы, помеченные как "требует шифрования", XmlKeyManager то будет выполнять эти элементы с помощью метода настроенногоIXmlEncryptorEncrypt, и он будет сохранять зашифрованный элемент, а не элемент обычного текста в объектеIXmlRepository. Выходные данные Encrypt метода — это EncryptedXmlInfo объект. Этот объект представляет собой оболочку, содержащую как результирующий зашифрованный XElement , так и тип, который представляет IXmlDecryptor собой объект, который можно использовать для расшифровки соответствующего элемента.

Существует четыре встроенных конкретных типа, реализующих IXmlEncryptor:

Дополнительные сведения см. в документе шифрования ключей.

Чтобы изменить механизм шифрования ключей по умолчанию на уровне приложения, зарегистрируйте пользовательский IXmlEncryptor экземпляр:

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

IXmlDecryptor

Интерфейс IXmlDecryptor представляет тип, который знает, как расшифровать расшифровку XElement , которая была зашифрована через объект IXmlEncryptor. Он предоставляет один API:

  • Decrypt(XElement encryptedElement) : XElement

Метод Decrypt отменяет шифрование, выполненное IXmlEncryptor.Encrypt. Как правило, каждая конкретная IXmlEncryptor реализация будет иметь соответствующую конкретную IXmlDecryptor реализацию.

Типы, которые реализуют IXmlDecryptor , должны иметь один из следующих двух открытых конструкторов:

  • .ctor(IServiceProvider)
  • .ctor()

Примечание.

Переданный IServiceProvider конструктору может иметь значение NULL.

IKeyEscrowSink

Интерфейс IKeyEscrowSink представляет тип, который может выполнять депонирования конфиденциальной информации. Помните, что сериализованные дескрипторы могут содержать конфиденциальную информацию (например, криптографический материал), и это привело к внедрению типа IXmlEncryptor в первую очередь. Однако аварии происходят, а круги ключей могут быть удалены или повреждены.

Интерфейс escrow предоставляет аварийный экранный люк, позволяя получить доступ к необработанным сериализованным XML, прежде чем он преобразуется любым настроенным IXmlEncryptor. Интерфейс предоставляет один API:

  • Store(Guid keyId, элемент XElement)

Это до IKeyEscrowSink реализации для обработки предоставленного элемента в безопасном режиме, согласованном с бизнес-политикой. Одна из возможных реализаций может быть для приемника escrow для шифрования XML-элемента с помощью известного корпоративного сертификата X.509, в котором был депонирован закрытый ключ сертификата; Тип CertificateXmlEncryptor может помочь с этим. Реализация IKeyEscrowSink также отвечает за сохранение предоставленного элемента соответствующим образом.

По умолчанию механизм депонирования не включен, хотя администраторы серверов могут настроить это глобально. Его также можно настроить программным способом IDataProtectionBuilder.AddKeyEscrowSink , как показано в приведенном ниже примере. Метод AddKeyEscrowSink перегружает зеркало IServiceCollection.AddSingleton и IServiceCollection.AddInstance перегрузки, так как IKeyEscrowSink экземпляры предназначены для одноэлементных. Если регистрируются несколько IKeyEscrowSink экземпляров, каждый из них будет вызываться во время создания ключей, поэтому ключи могут быть отложены в несколько механизмов одновременно.

Нет API для чтения материалов из экземпляра IKeyEscrowSink . Это согласуется с теорией проектирования механизма депонирования: она предназначена для того, чтобы сделать ключевой материал доступным для доверенного центра, и так как приложение само по себе не является доверенным центром, он не должен иметь доступа к своему собственному депонированного материала.

В следующем примере кода показано, как создать и зарегистрировать IKeyEscrowSink ключи, которые будут депонированы таким образом, чтобы восстановить их могут только члены contosoDomain Администратор s.

Примечание.

Чтобы запустить этот пример, необходимо быть на компьютере с Windows 8 или Windows Server 2012, а контроллер домена должен быть Windows Server 2012 или более поздней версии.

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