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


Поставщики хранилищ ключей в ASP.NET Core

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

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

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

Файловая система

Чтобы настроить репозиторий ключей на основе файловой системы, вызовите подпрограмму PersistKeysToFileSystem конфигурации, как показано ниже. Укажите указатель на репозиторий DirectoryInfo , в котором должны храниться ключи:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys\"));
}

Можно DirectoryInfo указать каталог на локальном компьютере или указать папку на сетевом ресурсе. Если рассматривать указание на каталог на локальном компьютере (и сценарий заключается в том, что только приложения на локальном компьютере требуют доступа к этому репозиторию), подумайте о использовании Windows DPAPI (в Windows) для шифрования ключей в состоянии покоя. В противном случае, рассмотрите возможность использования сертификата X.509 для шифрования ключей в состоянии покоя.

Хранилище Azure

ПакетAzure.Extensions.AspNetCore.DataProtection.Blobs NuGet предоставляет API для хранения ключей защиты данных в хранилище BLOB-объектов Azure. Ключи можно совместно использовать в нескольких экземплярах веб-приложения. Приложения могут совместно использовать файлы cookie проверки подлинности или защиту CSRF на нескольких серверах.

Примечание.

Рекомендации по добавлению пакетов в приложения .NET см. в статьях в разделе "Установка пакетов и управление пакетами" в рабочем процессе потребления пакетов (документация NuGet). Проверьте правильность версий пакета на сайте NuGet.org.

Чтобы взаимодействовать с Azure Key Vault локально с помощью учетных данных разработчика, войдите в учетную запись хранения в Visual Studio или войдите в Azure CLI. Если вы еще не установили Azure CLI, см. инструкции по установке Azure CLI. Следующую команду можно выполнить на панели PowerShell разработчика в Visual Studio или из командной оболочки, если не использовать Visual Studio:

az login

Дополнительные сведения см. в статье "Вход в Azure с помощью средств разработчика".

Настройте хранилище BLOB-объектов Azure для поддержки ключей защиты данных:

  • Создание учетной записи хранения Azure.

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

  • Рекомендуется использовать Azure Managed Identity и управление доступом на основе ролей (RBAC) для доступа к BLOB-объекту хранилища ключей. Вам не нужно создать файл ключа и отправить его в контейнер учетной записи хранения. Платформа создает файл для вас. Чтобы проверить содержимое файла ключа, используйте команду представления и редактирования контекстного меню в конце строки ключа на портале.

![ПРИМЕЧАНИЕ] Если вы планируете использовать URI BLOB-объекта с общей ключевой подписью (SAS) вместо управляемого Identity, используйте текстовый редактор для создания файла XML-ключа на вашем локальном компьютере.

<?xml version="1.0" encoding="utf-8"?>
<repository>
</repository>

Отправьте файл ключа в контейнер учетной записи хранения. Используйте команду контекстного меню View/edit в конце ключевой строки на портале, чтобы убедиться, что блоб содержит предыдущее содержимое. Создав файл вручную, вы можете получить универсальный код ресурса (URI) BLOB-объектов с помощью SAS на портале для настройки приложения на следующем шаге.

  • Создайте управляемую Identity Azure (или добавьте роль в существующий управляемый Identity объект, который планируется использовать) с ролью участника данных BLOB-объектов хранилища . Назначьте управляемый идентификатор Identity службе приложений Azure, в которой размещено развертывание: Параметры>Identity>Назначенные пользователем>Добавить.

    Примечание.

    Если вы также планируете локально запускать приложение с авторизованным пользователем для доступа к BLOB-объектам с помощью Azure CLI или проверки подлинности службы Azure Visual Studio, добавьте учетную запись пользователя Azure разработчика в службе управления доступом (IAM) с ролью участника данных BLOB-объектов хранилища . Если вы хотите использовать Azure CLI через Visual Studio, выполните az login команду на панели PowerShell разработчика и следуйте инструкциям по проверке подлинности с помощью клиента.

Чтобы настроить поставщика хранилища BLOB-объектов Azure, вызовите одну из PersistKeysToAzureBlobStorage перегрузок в приложении. В следующем примере используется перегрузка, которая принимает URI блоба и учетные данные токена (TokenCredential), полагаясь на управляемую идентификацию Azure Identity для управления доступом на основе ролей (RBAC).

Другие перегрузки основаны на:

  • URI BLOB-объекта и учетные данные для общего ключа доступа к хранилищу (StorageSharedKeyCredential).
  • Универсальный код ресурса (URI) для BLOB-объекта с подписанным ключом доступа (SAS).
  • Строка подключения, имя контейнера и имя блоба.
  • Клиент BLOB (BlobClient).

Дополнительные сведения об API и проверке подлинности пакета SDK Azure см. в статье "Проверка подлинности приложений .NET в службах Azure" с помощью библиотеки AzureIdentity. Инструкции по ведению журнала см. в статье "Ведение журнала с помощью пакета SDK Azure для .NET: ведение журнала без регистрации клиента". Для приложений, использующих внедрение зависимостей, можно вызвать AddAzureClientsCore, передавая true для enableLogForwarding, чтобы создать и соединить инфраструктуру журналирования.

В файле Program, где зарегистрированы службы:

TokenCredential? credential;

if (builder.Environment.IsProduction())
{
    credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
    // Local development and testing only
    DefaultAzureCredentialOptions options = new()
    {
        // Specify the tenant ID to use the dev credentials when running the app locally
        // in Visual Studio.
        VisualStudioTenantId = "{TENANT ID}",
        SharedTokenCacheTenantId = "{TENANT ID}"
    };

    credential = new DefaultAzureCredential(options);
}

builder.Services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential);

{MANAGED IDENTITY CLIENT ID}: идентификатор управляемого Identity клиента Azure (GUID).

{TENANT ID}: идентификатор клиента.

{APPLICATION NAME}: SetApplicationName задает уникальное имя этого приложения в системе защиты данных. Значение должно совпадать между развертываниями приложения.

{BLOB URI}: полный унифицированный идентификатор ресурса (URI) к файлу ключа. Универсальный код ресурса (URI) создается службой хранилища Azure при создании файла ключа. Не используйте SAS.

Альтернативный подход с общедоступным подписанным URL-адресом (SAS): в качестве альтернативы использованию управляемого Identity для доступа к ключевому BLOB-объекту в хранилище Azure Blob, можно вызвать PersistKeysToAzureBlobStorage перегрузку метода, принимающего URI BLOB-объекта с SAS-токеном:

builder.Services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"));

В Startup.ConfigureServices:

TokenCredential? credential;

if (_env.IsProduction())
{
    credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
    // Local development and testing only
    DefaultAzureCredentialOptions options = new()
    {
        // Specify the tenant ID to use the dev credentials when running the app locally
        // in Visual Studio.
        VisualStudioTenantId = "{TENANT ID}",
        SharedTokenCacheTenantId = "{TENANT ID}"
    };

    credential = new DefaultAzureCredential(options);
}

services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential);

{MANAGED IDENTITY CLIENT ID}: идентификатор управляемого Identity клиента Azure (GUID).

{TENANT ID}: идентификатор клиента.

{APPLICATION NAME}: SetApplicationName задает уникальное имя этого приложения в системе защиты данных. Значение должно совпадать между развертываниями приложения.

{BLOB URI}: полный унифицированный идентификатор ресурса (URI) к файлу ключа. Универсальный код ресурса (URI) создается службой хранилища Azure при создании файла ключа. Не используйте SAS.

Пример:

https://contoso.blob.core.windows.net/data-protection/keys.xml

Альтернативный подход с общедоступным подписанным URL-адресом (SAS): в качестве альтернативы использованию управляемого Identity для доступа к ключевому BLOB-объекту в хранилище Azure Blob, можно вызвать PersistKeysToAzureBlobStorage перегрузку метода, принимающего URI BLOB-объекта с SAS-токеном:

services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"));

{APPLICATION NAME}: SetApplicationName задает уникальное имя этого приложения в системе защиты данных. Значение должно совпадать между развертываниями приложения.

{BLOB URI WITH SAS}: полный URI, в котором файл ключа должен храниться с маркером SAS в качестве параметра строки запроса. URI создается службой хранилища Azure при запросе SAS для загруженного файла ключа. В следующем примере имя контейнера — data-protectionи имя contosoучетной записи хранения. Файл ключа называется keys.xml. Строка запроса с общей подписью доступа (SAS) находится в конце URI ({SHARED ACCESS SIGNATURE} заполнитель).

Пример:

https://contoso.blob.core.windows.net/data-protection/keys.xml{SHARED ACCESS SIGNATURE}

Если веб-приложение работает в качестве службы Azure, строка подключения может использоваться для аутентификации в Azure Storage с помощью BlobContainerClient, как показано в следующем примере.

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

В этой статье показано использование строк подключения. С локальной базой данных пользователю не требуется аутентификация, но в рабочей среде в строку подключения иногда включается пароль для аутентификации. Учетные данные владельца ресурса (ROPC) — это риск безопасности, который следует избежать в рабочих базах данных. Рабочие приложения должны использовать самый безопасный поток проверки подлинности. Дополнительные сведения о проверке подлинности для приложений, развернутых в тестовых или рабочих средах, см. в разделе "Безопасные потоки проверки подлинности".

Необязательный вызов CreateIfNotExistsAsync автоматически подготавливает контейнер, если он не существует.

Строку подключения ({CONNECTION STRING} метка) к учетной записи хранения можно найти на портале Entra или Azure в разделе "Ключи доступа" или с помощью следующей команды Azure CLI:

az storage account show-connection-string --name <account_name> --resource-group <resource_group>

В файле Program, где зарегистрированы службы:

string connectionString = "{CONNECTION STRING}";
string containerName = "{CONTAINER NAME}";
string blobName = "keys.xml";
var container = new BlobContainerClient(connectionString, containerName);
await container.CreateIfNotExistsAsync();
BlobClient blobClient = container.GetBlobClient(blobName);

builder.Services.AddDataProtection().PersistKeysToAzureBlobStorage(blobClient);

В Startup.ConfigureServices:

string connectionString = "{CONNECTION STRING}";
string containerName = "{CONTAINER NAME}";
string blobName = "keys.xml";
var container = new BlobContainerClient(connectionString, containerName);
await container.CreateIfNotExistsAsync();
BlobClient blobClient = container.GetBlobClient(blobName);

services.AddDataProtection().PersistKeysToAzureBlobStorage(blobClient);

Редис

Пакет Microsoft.AspNetCore.DataProtection.StackExchangeRedis позволяет хранить ключи защиты данных в кэше Redis. Ключи можно совместно использовать в нескольких экземплярах веб-приложения. Приложения могут совместно использовать файлы cookie проверки подлинности или защиту CSRF на нескольких серверах.

Пакет Microsoft.AspNetCore.DataProtection.Redis позволяет хранить ключи защиты данных в кэше Redis. Ключи можно совместно использовать в нескольких экземплярах веб-приложения. Приложения могут совместно использовать файлы cookie проверки подлинности или защиту CSRF на нескольких серверах.

Чтобы настроить Redis, вызовите одну из PersistKeysToStackExchangeRedis перегрузок:

public void ConfigureServices(IServiceCollection services)
{
    var redis = ConnectionMultiplexer.Connect("<URI>");
    services.AddDataProtection()
        .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys");
}

Чтобы настроить Redis, вызовите одну из PersistKeysToRedis перегрузок:

public void ConfigureServices(IServiceCollection services)
{
    var redis = ConnectionMultiplexer.Connect("<URI>");
    services.AddDataProtection()
        .PersistKeysToRedis(redis, "DataProtection-Keys");
}

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

Реестр

Применяется только к развертываниям Windows.

Иногда приложение может не иметь доступа на запись к файловой системе. Рассмотрим сценарий, в котором приложение работает под учетной записью виртуальной службы (например, под идентификатором пула приложений w3wp.exe). В таких случаях администратор может предоставить раздел реестра, к которому может обращаться удостоверение учетной записи службы. PersistKeysToRegistry Вызовите метод расширения, как показано ниже. RegistryKey Укажите расположение, в котором должны храниться криптографические ключи:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Sample\keys", true));
}

Внимание

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

Платформа Entity Framework Core

Пакет Microsoft.AspNetCore.DataProtection.EntityFrameworkCore предоставляет механизм хранения ключей защиты данных в базе данных с помощью Entity Framework Core. Пакет Microsoft.AspNetCore.DataProtection.EntityFrameworkCore NuGet должен быть добавлен в файл проекта, он не является частью метапакета Microsoft.AspNetCore.App.

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

Чтобы настроить EF Core поставщика, вызовите PersistKeysToDbContext метод:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    // Add a DbContext to store your Database Keys
    services.AddDbContext<MyKeysContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("MyKeysConnection")));

    // using Microsoft.AspNetCore.DataProtection;
    services.AddDataProtection()
        .PersistKeysToDbContext<MyKeysContext>();

    services.AddDefaultIdentity<IdentityUser>()
        .AddDefaultUI(UIFramework.Bootstrap4)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

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

Универсальный параметр TContext должен наследоваться от DbContext и реализовать IDataProtectionKeyContext:

using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using WebApp1.Data;

namespace WebApp1
{
    class MyKeysContext : DbContext, IDataProtectionKeyContext
    {
        // A recommended constructor overload when using EF Core 
        // with dependency injection.
        public MyKeysContext(DbContextOptions<MyKeysContext> options) 
            : base(options) { }

        // This maps to the table that stores keys.
        public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
    }
}

Создайте DataProtectionKeys таблицу.

Выполните следующие команды в окне консоли диспетчер пакетов (PMC):

Add-Migration AddDataProtectionKeys -Context MyKeysContext
Update-Database -Context MyKeysContext

MyKeysContext является DbContext, определяемым в предыдущем примере кода. Если вы используете DbContext с другим именем, замените ваше имя DbContext на MyKeysContext.

Класс DataProtectionKeys или сущность принимает структуру, показанную в следующей таблице.

Свойство/поле Тип CLR Тип SQL
Id int int, PK, IDENTITY(1,1)не null
FriendlyName string nvarchar(MAX)нулевой
Xml string nvarchar(MAX)нулевой

Настраиваемый репозиторий ключей

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