Управление ключами в ASP.NET Core

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

  • Создан — ключ существует в кольце, но еще не активирован. Ключ не должен использоваться для новых операций защиты, пока не истечет достаточно времени, пока у ключа есть шанс распространить на все компьютеры, использующие этот звонок.

  • Активный — ключ существует в кольце ключа и должен использоваться для всех новых операций защиты.

  • Срок действия истек. ключ запускал свое естественное время существования и больше не должен использоваться для новых операций защиты.

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

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

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

Разработчик может удалить ключ из круга ключей (например, удалив соответствующий файл из файловой системы). На этом этапе все данные, защищенные ключом, не будут расшифрованы, и аварийное переопределение, как и у отмененных ключей, отсутствует. Удаление ключа — это действительно разрушительное поведение, поэтому система защиты данных не предоставляет API первого класса для выполнения этой операции.

Выбор ключа по умолчанию

Когда система защиты данных считывает ключ кольца из резервного репозитория, она попытается выполнить обнаружение ключа "по умолчанию" из кольца ключа. Ключ по умолчанию используется для новых операций защиты.

Общий эвристический подход заключается в том, что система защиты данных выбирает ключ с самой последней датой активации в качестве ключа по умолчанию. (Существует небольшой параметр фактор, позволяющий отклонять часы "сервер-сервер".) Если срок действия ключа истек или он отозван, и если приложение не отключило автоматическое создание ключей, будет создан новый ключ с немедленной активацией в соответствии с истечением срока действия ключа и политикой отката .

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

Существует исключение. Если разработчик приложения отключил автоматическое создание ключей, система защиты данных должна выбрать что-то в качестве ключа по умолчанию. В этом сценарии система выберет неотозванный ключ с самой последней датой активации и имеет предпочтение, предоставленное ключам, которые имели время для распространения на другие компьютеры в кластере. В качестве результата резервной системы может быть выбран ключ по умолчанию с истекшим сроком действия. Резервная система никогда не будет выбирать отозванный ключ в качестве ключа по умолчанию, и если ключ звонка пуст или каждый ключ был отозван, система выдаст ошибку при инициализации.

Срок действия ключа и его откат

При создании ключа автоматически назначается дата активации {Now + 2 дня} и Дата окончания срока действия {Now + 90 дн.}. 2-дневная задержка перед активацией дает ключевое время для распространения по системе. Это значит, что другие приложения, указывающие на резервное хранилище, смогут наблюдать за ключом в следующем периоде автоматического обновления, таким образом уменьшая вероятность того, что при активации ключевого звонка он распространяется на все приложения, которым может потребоваться его использовать.

Если срок действия ключа по умолчанию истекает в течение двух дней, и если у этого звонка еще нет ключа, который будет активным после истечения срока действия ключа по умолчанию, система защиты данных автоматически сохранит новый ключ в кольце ключа. Этот новый ключ имеет дату активации {срок действия ключа по умолчанию} и дату окончания срока действия {Now + 90 дн.}. Это позволяет системе автоматически выполнять откат ключей на регулярной основе без прерывания обслуживания.

Могут возникнуть обстоятельства, при которых ключ будет создан с немедленной активацией. Одним из примеров может быть то, что приложение не выполнялось в течение времени, и срок действия всех ключей в кольце истек. В этом случае ключу присваивается Дата активации {Now} без обычной задержки активации в 2 дня.

Время жизни ключа по умолчанию составляет 90 дней, хотя это можно настроить, как показано в следующем примере.

services.AddDataProtection()
       // use 14-day lifetime instead of 90-day lifetime
       .SetDefaultKeyLifetime(TimeSpan.FromDays(14));

Администратор также может изменить масштаб всей системы по умолчанию, хотя явный вызов SetDefaultKeyLifetime переопределит любую системную политику. Время жизни ключа по умолчанию не может быть короче 7 дней.

Автоматическое обновление Key Ring

При инициализации системы защиты данных она считывает ключевое кольцо из базового репозитория и кэширует его в памяти. Этот кэш позволяет выполнять операции защиты и снятия защиты без обращения к резервному хранилищу. Система автоматически проверит резервное хранилище на наличие изменений приблизительно каждые 24 часа или по истечении срока действия текущего ключа по умолчанию, в зависимости от того, что происходит раньше.

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

Разработчики должны очень редко (если всегда) использовать API управления ключами напрямую. Система защиты данных будет выполнять автоматическое управление ключами, как описано выше.

Система защиты данных предоставляет интерфейс IKeyManager , который можно использовать для проверки и внесения изменений в кольцо ключа. Система DI, IDataProtectionProvider предоставляющая экземпляр, может также предоставлять экземпляр IKeyManager для использования. Кроме того, можно извлечь IKeyManager прямо из, IServiceProvider как в примере ниже.

Любая операция, которая изменяет кольцо ключа (создание нового ключа явным образом или выполнение отзыва), сделает кэш в памяти недействительным. Следующий вызов функции Protect или приведет к тому, что Unprotect система защиты данных прочитает ключ звонка и воссоздаст кэш.

В приведенном ниже примере демонстрируется использование IKeyManager интерфейса для проверки и управления кругом ключей, включая отзыв существующих ключей и создание нового ключа вручную.

using System;
using System.IO;
using System.Threading;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.DependencyInjection;

public class Program
{
    public static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddDataProtection()
            // point at a specific folder and use DPAPI to encrypt keys
            .PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
            .ProtectKeysWithDpapi();
        var services = serviceCollection.BuildServiceProvider();

        // perform a protect operation to force the system to put at least
        // one key in the key ring
        services.GetDataProtector("Sample.KeyManager.v1").Protect("payload");
        Console.WriteLine("Performed a protect operation.");
        Thread.Sleep(2000);

        // get a reference to the key manager
        var keyManager = services.GetService<IKeyManager>();

        // list all keys in the key ring
        var allKeys = keyManager.GetAllKeys();
        Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
        foreach (var key in allKeys)
        {
            Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}");
        }

        // revoke all keys in the key ring
        keyManager.RevokeAllKeys(DateTimeOffset.Now, reason: "Revocation reason here.");
        Console.WriteLine("Revoked all existing keys.");

        // add a new key to the key ring with immediate activation and a 1-month expiration
        keyManager.CreateNewKey(
            activationDate: DateTimeOffset.Now,
            expirationDate: DateTimeOffset.Now.AddMonths(1));
        Console.WriteLine("Added a new key.");

        // list all keys in the key ring
        allKeys = keyManager.GetAllKeys();
        Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
        foreach (var key in allKeys)
        {
            Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}");
        }
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Performed a protect operation.
 * The key ring contains 1 key(s).
 * Key {1b948618-be1f-440b-b204-64ff5a152552}: Created = 2015-03-18 22:20:49Z, IsRevoked = False
 * Revoked all existing keys.
 * Added a new key.
 * The key ring contains 2 key(s).
 * Key {1b948618-be1f-440b-b204-64ff5a152552}: Created = 2015-03-18 22:20:49Z, IsRevoked = True
 * Key {2266fc40-e2fb-48c6-8ce2-5fde6b1493f7}: Created = 2015-03-18 22:20:51Z, IsRevoked = False
 */

Если вы хотите увидеть комментарии к коду, переведенные на языки, отличные от английского, сообщите нам на странице обсуждения этой проблемы на сайте GitHub.

Хранилище ключей

Система защиты данных имеет эвристический подход, позволяющий автоматически вычислить подходящее место хранения ключа и механизм шифрования неактивных ключей. Механизм сохраняемости ключей также настраивается разработчиком приложения. В следующих документах рассматриваются встроенные реализации этих механизмов.