Управление ключами в ASP.NET Core
Система защиты данных автоматически управляет временем существования master ключей, используемых для защиты и отмены защиты полезных данных. Каждый ключ может существовать в одном из четырех этапов:
Создано — ключ существует в круге ключей, но еще не активирован. Ключ не следует использовать для новых операций Защиты до тех пор, пока не прошло достаточно времени, чтобы ключ мог распространиться на все компьютеры, использующие этот круг ключей.
Активный — ключ существует в круге ключей и должен использоваться для всех новых операций защиты.
Истек срок действия — ключ имеет естественное время существования и больше не должен использоваться для новых операций защиты.
Отозвано — ключ скомпрометирован и не должен использоваться для новых операций защиты.
Созданные, активные ключи и ключи с истекшим сроком действия могут использоваться для отмены защиты входящих полезных данных. Отозванные ключи по умолчанию не могут использоваться для отмены защиты полезных данных, но разработчик приложения может переопределить это поведение при необходимости.
Предупреждение
У разработчика может возникнуть соблазн удалить ключ из круга ключей (например, удалив соответствующий файл из файловой системы). На этом этапе все данные, защищенные ключом, окончательно не расшифровываются, и нет экстренного переопределения, как с отозванными ключами. Удаление ключа действительно является разрушительным поведением, и, следовательно, система защиты данных не предоставляет первоклассный API для выполнения этой операции.
Выбор ключа по умолчанию
Когда система защиты данных считывает круг ключей из резервного репозитория, она попытается найти ключ по умолчанию из круга ключей. Ключ по умолчанию используется для новых операций Защиты.
Общая эвристика заключается в том, что система защиты данных выбирает ключ с самой последней датой активации в качестве ключа по умолчанию. (Существует небольшой фактор смеха, допускающий неравномерное распределение часов между серверами.) Если срок действия ключа истек или отозван, а приложение не отключило автоматическое создание ключа, будет создан новый ключ с немедленной активацией в зависимости от указанной ниже политики истечения срока действия ключа и последовательной политики.
Причина, по которой система защиты данных создает новый ключ немедленно, а не возвращается к другому ключу, заключается в том, что новое поколение ключей следует рассматривать как неявное истечение срока действия всех ключей, которые были активированы до нового ключа. Общая идея заключается в том, что новые ключи, возможно, были настроены с использованием других алгоритмов или механизмов шифрования неактивных ключей, чем старые ключи, и система должна предпочесть текущую конфигурацию, а не отката.
Есть исключение. Если разработчик приложения отключил автоматическое создание ключей, система защиты данных должна выбрать что-то в качестве ключа по умолчанию. В этом резервном сценарии система выберет неизозванный ключ с самой последней датой активации, отдавая предпочтение ключам, которые успели распространить на другие компьютеры в кластере. Резервная система может в конечном итоге выбрать просроченный ключ по умолчанию. Резервная система никогда не выберет отозванный ключ в качестве ключа по умолчанию. Если круг ключей пуст или все ключи были отозваны, система выдает ошибку при инициализации.
Истечение срока действия и смена ключей
При создании ключа автоматически присваивается дата активации { now + 2 days } и дата окончания срока действия { now + 90 дней }. 2-дневная задержка перед активацией дает ключу время для распространения в системе. Это позволяет другим приложениям, указывающим на резервное хранилище, наблюдать за ключом в следующий период автоматического обновления, тем самым повышая вероятность того, что, когда кольцо ключей становится активным, оно распространяется на все приложения, которым может потребоваться его использовать.
Если срок действия ключа по умолчанию истекает в течение 2 дней и если в круге ключей еще нет ключа, который будет активен после истечения срока действия ключа по умолчанию, система защиты данных автоматически сохранит новый ключ в круге ключей. Этот новый ключ имеет дату активации { дата окончания срока действия ключа по умолчанию } и дату окончания срока действия { now + 90 дней }. Это позволяет системе автоматически сменять ключи на регулярной основе без прерывания обслуживания.
В некоторых случаях ключ будет создан с немедленной активацией. Например, приложение не запускается в течение определенного времени и срок действия всех ключей в круге ключей истек. В этом случае ключу присваивается дата активации { now } без обычной 2-дневной задержки активации.
Время существования ключа по умолчанию составляет 90 дней, хотя это можно настроить, как показано в следующем примере.
services.AddDataProtection()
// use 14-day lifetime instead of 90-day lifetime
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
Администратор также может изменить общесистемную политику по умолчанию, хотя явный вызов SetDefaultKeyLifetime
переопределяет любую общесистемную политику. Время существования ключа по умолчанию не может быть короче 7 дней.
Автоматическое обновление круга ключей
Когда система защиты данных инициализируется, она считывает круг ключей из базового репозитория и кэширует его в памяти. Этот кэш позволяет выполнять операции защиты и отмены защиты без попадания в резервное хранилище. Система будет автоматически проверка резервное хранилище для изменений примерно каждые 24 часа или по истечении срока действия текущего ключа по умолчанию, в зависимости от того, что произойдет раньше.
Предупреждение
Разработчики должны очень редко (если вообще-либо) использовать API-интерфейсы управления ключами напрямую. Система защиты данных будет выполнять автоматическое управление ключами, как описано выше.
Система защиты данных предоставляет интерфейс IKeyManager
, который можно использовать для проверки и внесения изменений в круг ключей. Система внедрения зависимостей, которая предоставила экземпляр , IDataProtectionProvider
также может предоставить экземпляр IKeyManager
для вашего использования. Кроме того, можно извлечь IKeyManager
объект прямо из , IServiceProvider
как показано в примере ниже.
Любая операция, изменяющая круг ключей (создание нового ключа явным образом или выполнение отзыва), сделает кэш в памяти недействительным. Следующий вызов или Unprotect
приведет к Protect
тому, что система защиты данных перечитает круг ключей и повторно создаст кэш.
В приведенном ниже примере показано использование 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.
Хранилище ключей
Система защиты данных имеет эвристическую ошибку, при которой она пытается автоматически определить подходящее расположение хранения ключей и механизм шифрования неактивных данных. Механизм сохраняемости ключей также настраивается разработчиком приложения. В следующих документах рассматриваются встроенные реализации этих механизмов.