Поделиться через


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

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

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

Ключ

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

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

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

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

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

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

Примечание.

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

IKeyManager

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

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

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

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

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

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

XmlKeyManager

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Извлечение ключей / 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:

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

Чтобы изменить стандартный механизм шифрования ключей поrest умолчанию, зарегистрируйте пользовательский 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 Admins могут их восстановить.

Примечание.

Чтобы запустить этот пример, необходимо быть на компьютере с 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>
 */