Настройка защиты данных в ASP.NET Core
При инициализации системы защиты данных она применяет параметры по умолчанию в зависимости от операционной среды. Эти параметры подходят для приложений, работающих на одном компьютере. Однако есть случаи, когда разработчику может потребоваться изменить параметры по умолчанию:
- Приложение распространяется на несколько компьютеров.
- По соображениям соответствия требованиям.
В этих сценариях система защиты данных предлагает широкий API конфигурации.
Предупреждение
Как и в файлах конфигурации, кольцо ключей защиты данных должно быть защищено с помощью соответствующих разрешений. Вы можете зашифровать ключи по restадресу, но это не препятствует кибератакам создавать новые ключи. Следовательно, это влияет на безопасность вашего приложения. Расположение хранилища, настроенного с помощью Data Protection, должно иметь доступ к самому приложению, аналогично тому, как вы будете защищать файлы конфигурации. Например, если вы решили сохранить кольцо ключей на диске, используйте разрешения файловой системы. Убедитесь, что только в identity том, в каком веб-приложении запущено чтение, запись и создание доступа к этому каталогу. При использовании Хранилище BLOB-объектов Azure только веб-приложение должно иметь возможность читать, записывать или создавать новые записи в хранилище BLOB-объектов и т. д.
Метод AddDataProtection расширения возвращает IDataProtectionBuilderзначение . IDataProtectionBuilder
предоставляет методы расширения, которые можно объединить для настройки параметров защиты данных.
Примечание.
Эта статья была написана для приложения, работающего в контейнере Docker. В контейнере Docker приложение всегда имеет одинаковый путь и, следовательно, одно и то же приложение дискриминационным. Приложения, которые должны выполняться в нескольких средах (например, локальные и развернутые), должны задать дискриминатор приложений по умолчанию для среды. Запуск приложения в нескольких средах выходит за рамки этой статьи.
Для расширений защиты данных, используемых в этой статье, требуются следующие пакеты NuGet:
ProtectKeysWithAzureKeyVault
Войдите в Azure с помощью интерфейса командной строки, например:
az login
Чтобы управлять ключами с помощью Azure Key Vault, настройте систему в Program.cs
ProtectKeysWithAzureKeyVault . blobUriWithSasToken
— полный универсальный код ресурса (URI), в котором должен храниться файл ключа. Универсальный код ресурса (URI) должен содержать маркер SAS в качестве параметра строки запроса:
builder.Services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
Для взаимодействия и авторизации приложения с помощью KeyVault необходимо добавить пакет AzureIdentity .
Задайте расположение хранилища кольца ключей (например, PersistKeysToAzureBlobStorage). Необходимо задать расположение, так как вызов ProtectKeysWithAzureKeyVault
реализует параметры автоматической IXmlEncryptor защиты данных, включая расположение хранилища кольца ключей. В предыдущем примере используется Хранилище BLOB-объектов Azure для сохранения кольца ключей. Дополнительные сведения см. в разделе поставщиков хранилища ключей: служба хранилища Azure. Вы также можете сохранить кольцо ключей локально с помощью PersistKeysToFileSystem.
Это keyIdentifier
идентификатор ключа хранилища ключей, используемый для шифрования ключей. Например, ключ, созданный в хранилище ключей с именем dataprotection
в contosokeyvault
идентификаторе ключа https://contosokeyvault.vault.azure.net/keys/dataprotection/
. Предоставьте приложению разрешения Get, Unwrap Key и Wrap Key в хранилище ключей.
ProtectKeysWithAzureKeyVault
Перегрузки:
- ProtectKeysWithAzureKeyVault(IDataProtectionBuilder, Uri, TokenCredential) позволяет использовать URI keyIdentifier и tokenCredential, чтобы система защиты данных могли использовать хранилище ключей.
- ProtectKeysWithAzureKeyVault(IDataProtectionBuilder, String, IKeyEncryptionKeyResolver) позволяет использовать строку keyIdentifier и IKeyEncryptionKeyResolver, чтобы система защиты данных могли использовать хранилище ключей.
Если приложение использует старые пакеты Azure (Microsoft.AspNetCore.DataProtection.AzureStorage и Microsoft.AspNetCore.DataProtection.AzureKeyVault), рекомендуется удалить эти ссылки и обновить их до Azure.Extensions.AspNetCore.DataProtection.Blobs и Azure.Extensions.AspNetCore.DataProtection.Keys. Эти пакеты содержат новые обновления и устраняют некоторые ключевые проблемы с безопасностью и стабильностью старых пакетов.
builder.Services.AddDataProtection()
// This blob must already exist before the application is run
.PersistKeysToAzureBlobStorage("<storageAccountConnectionString", "<containerName>", "<blobName>")
// Removing this line below for an initial run will ensure the file is created correctly
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
PersistKeysToFileSystem
Чтобы хранить ключи в UNC-ресурсе вместо расположения %LOCALAPPDATA% по умолчанию, настройте систему с помощью PersistKeysToFileSystem:
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
Предупреждение
Если изменить расположение сохраняемости ключа, система больше не шифрует ключи restпо адресу, так как он не знает, является ли DPAPI соответствующим механизмом шифрования.
PersistKeysToDbContext
Чтобы сохранить ключи в базе данных с помощью EntityFramework, настройте систему с помощью пакета Microsoft.AspNetCore.DataProtection.EntityFrameworkCore :
builder.Services.AddDataProtection()
.PersistKeysToDbContext<SampleDbContext>();
Предыдущий код хранит ключи в настроенной базе данных. Контекст базы данных, используемый, должен реализовать IDataProtectionKeyContext
. IDataProtectionKeyContext
предоставляет свойство DataProtectionKeys
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
Это свойство представляет таблицу, в которой хранятся ключи. Создайте таблицу вручную или с помощью DbContext
миграций. Дополнительные сведения см. в разделе DataProtectionKey.
ProtectKeysWith*
Систему можно настроить для защиты ключей, rest вызвав любой из API конфигурации ProtectKeysWith* . Рассмотрим приведенный ниже пример, в котором хранятся ключи в UNC-ресурсе и шифруются эти ключи rest с определенным сертификатом X.509:
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);
Вы можете предоставить сертификат, загруженный X509Certificate2 ProtectKeysWithCertificateиз файла:
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));
Дополнительные примеры и обсуждение встроенных механизмов шифрования ключей см. в разделе "Шифрование Rest ключей".
UnprotectKeysWithAnyCertificate
Вы можете повернуть сертификаты и расшифровать ключи rest с помощью массива X509Certificate2 сертификатов с UnprotectKeysWithAnyCertificateпомощью:
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]))
.UnprotectKeysWithAnyCertificate(
new X509Certificate2("certificate_1.pfx", builder.Configuration["CertificatePassword_1"]),
new X509Certificate2("certificate_2.pfx", builder.Configuration["CertificatePassword_2"]));
SetDefaultKeyLifetime
Чтобы настроить систему для использования времени существования ключа в течение 14 дней вместо 90 дней по умолчанию, используйте SetDefaultKeyLifetimeследующую команду:
builder.Services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
SetApplicationName
По умолчанию система защиты данных изолирует приложения друг от друга на основе корневых путей содержимого, даже если они совместно используют один и тот же репозиторий физических ключей. Эта изоляция запрещает приложениям понимать защищенные полезные данные друг друга.
Для совместного использования защищенных полезных данных между приложениями:
- Настройте SetApplicationName в каждом приложении одинаковое значение.
- Используйте ту же версию стека API защиты данных в приложениях. Выполните одно из следующих действий в файлах проектов приложений:
- Ссылка на ту же общую версию платформы с помощью метапакета Microsoft.AspNetCore.App.
- Ссылка на ту же версию пакета защиты данных.
builder.Services.AddDataProtection()
.SetApplicationName("<sharedApplicationName>");
SetApplicationName внутренние наборы DataProtectionOptions.ApplicationDiscriminator. В целях устранения неполадок значение, назначенное дискриминационным платформой, можно регистрироваться со следующим кодом, помещенным после WebApplication сборки Program.cs
:
var discriminator = app.Services.GetRequiredService<IOptions<DataProtectionOptions>>()
.Value.ApplicationDiscriminator;
app.Logger.LogInformation("ApplicationDiscriminator: {ApplicationDiscriminator}", discriminator);
Дополнительные сведения о том, как используется дискриминация, см. в следующих разделах ниже в этой статье:
Предупреждение
В .NET 6 WebApplicationBuilder нормализует корневой путь содержимого, чтобы завершиться с DirectorySeparatorCharпомощью . Например, в Windows корневой путь содержимого заканчивается и в \
Linux /
. Другие узлы не нормализуют путь. Большинство приложений, которые переносятся из HostBuilder или не будут совместно использовать одно и WebHostBuilder то же имя приложения, так как они не будут завершающимися DirectorySeparatorChar
. Чтобы обойти эту проблему, удалите символ разделителя каталогов и задайте имя приложения вручную, как показано в следующем коде:
using Microsoft.AspNetCore.DataProtection;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
var trimmedContentRootPath = builder.Environment.ContentRootPath.TrimEnd(Path.DirectorySeparatorChar);
builder.Services.AddDataProtection()
.SetApplicationName(trimmedContentRootPath);
var app = builder.Build();
app.MapGet("/", () => Assembly.GetEntryAssembly()!.GetName().Name);
app.Run();
DisableAutomaticKeyGeneration
Возможно, у вас есть сценарий, в котором приложение не хочет автоматически свернуть ключи (создать новые ключи) по мере истечения срока действия. Одним из примеров этого сценария может быть приложение, настроенное в первичной или вторичной связи, где только основное приложение отвечает за проблемы управления ключами, а вторичные приложения просто имеют представление только для чтения кольца ключей. Вторичные приложения можно настроить для обработки кольца ключей только для чтения, настроив систему с помощью DisableAutomaticKeyGeneration:
builder.Services.AddDataProtection()
.DisableAutomaticKeyGeneration();
Изоляция для каждого приложения
Если система защиты данных предоставляется узлом ASP.NET Core, она автоматически изолирует приложения друг от друга, даже если эти приложения выполняются под одной учетной записью рабочего процесса и используют один и тот же главный материал ключей. Это аналогично модификатору IsolateApps из элемента System.Web <machineKey>
.
Механизм изоляции работает путем рассмотрения каждого приложения на локальном компьютере в качестве уникального клиента, таким образом IDataProtector , корневой каталог для любого конкретного приложения автоматически включает идентификатор приложения в качестве дискриминационных (ApplicationDiscriminator). Уникальный идентификатор приложения — это физический путь приложения:
- Для приложений, размещенных в IIS, уникальный идентификатор — это физический путь к приложению IIS. Если приложение развертывается в среде веб-фермы, это значение стабильно предполагает, что среды IIS настроены одинаково на всех компьютерах в веб-ферме.
- Для локальных приложений, работающих на сервереKestrel, уникальный идентификатор — это физический путь к приложению на диске.
Уникальный идентификатор предназначен для выживания сбросов как отдельного приложения, так и самого компьютера.
Этот механизм изоляции предполагает, что приложения не являются вредоносными. Вредоносное приложение всегда может повлиять на любое другое приложение, работающее в той же учетной записи рабочего процесса. В общей среде размещения, в которой приложения являются взаимонадежными, поставщик размещения должен предпринять шаги, чтобы обеспечить изоляцию на уровне ОС между приложениями, включая разделение базовых репозиториев ключей приложений.
Если система защиты данных не предоставляется узлом ASP.NET Core (например, если создать экземпляр с помощью конкретного типа) изоляция приложений DataProtectionProvider
отключена по умолчанию. Если изоляция приложений отключена, все приложения, поддерживаемые одним и тем же материалом ключей, могут совместно использовать полезные данные, если они предоставляют соответствующие цели. Чтобы обеспечить изоляцию приложений в этой среде, вызовите SetApplicationName
метод в объекте конфигурации и укажите уникальное имя для каждого приложения.
Защита данных и изоляция приложений
Рассмотрим следующие моменты для изоляции приложений:
При указании нескольких приложений в одном репозитории ключей намерение заключается в том, что приложения используют один и тот же главный материал ключа. Защита данных разрабатывается с предположением, что все приложения, совместно использующие кольцо ключей, могут получить доступ ко всем элементам в этом круге ключей. Уникальный идентификатор приложения используется для изоляции определенных ключей приложения, производных от предоставленных ключей. Он не ожидает, что разрешения на уровне элементов, такие как предоставленные Azure KeyVault, будут использоваться для принудительной дополнительной изоляции. При попытке разрешения уровня элементов возникают ошибки приложения. Если вы не хотите полагаться на встроенную изоляцию приложений, следует использовать отдельные расположения хранилища ключей и не предоставлять общий доступ между приложениями.
Дискриминатор приложения (ApplicationDiscriminator) используется для предоставления разным приложениям общего доступа к одному и тому же материалу главного ключа, но для сохранения их криптографических полезных данных, отличных друг от друга. Чтобы приложения могли читать криптографические полезные данные друг друга, они должны иметь одинаковые дискриминационные приложения, которые можно задать путем вызова
SetApplicationName
.Если приложение скомпрометировано (например, атакой RCE), все основные материалы ключей, доступные для этого приложения, также должны считаться скомпрометированы независимо от состояния защитыrest . Это означает, что если два приложения указываются на один репозиторий, даже если они используют разные дискриминационные приложения, компрометация одного из них функционально эквивалентна компромиссу обоих.
Это "функционально эквивалентно компромиссу обоих" предложений, даже если два приложения используют разные механизмы для защиты ключей.rest Как правило, это не ожидаемая конфигурация. Механизм защиты предназначен для обеспечения защитыrest в случае, если кибератака получает доступ на чтение к репозиторию. Кибератака, которая получает доступ к репозиторию на запись (возможно, из-за того, что они достигли разрешения на выполнение кода в приложении), может вставить вредоносные ключи в хранилище. Система защиты данных намеренно не обеспечивает защиту от кибератаки, который получает доступ на запись в репозиторий ключей.
Если приложения должны оставаться действительно изолированными друг от друга, они должны использовать разные репозитории ключей. Это естественно выходит из определения "изолированных". Приложения не изолированы, если у всех них есть доступ на чтение и запись к хранилищам данных друг друга.
Изменение алгоритмов с помощью UseCryptographicAlgorithms
Стек защиты данных позволяет изменить алгоритм по умолчанию, используемый только что созданными ключами. Самый простой способ сделать это — вызвать из обратного вызова UseCryptographicAlgorithms конфигурации:
builder.Services.AddDataProtection()
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
Значение по умолчанию EncryptionAlgorithm — AES-256-CBC, а значение по умолчанию ValidationAlgorithm — HMACSHA256. Политика по умолчанию может быть задана системным администратором с помощью политики на уровне компьютера, но явный вызов UseCryptographicAlgorithms
для переопределения политики по умолчанию.
Вызов UseCryptographicAlgorithms
позволяет указать требуемый алгоритм из предопределенного встроенного списка. Вам не нужно беспокоиться о реализации алгоритма. В приведенном выше сценарии система защиты данных пытается использовать реализацию AES CNG при запуске в Windows. В противном случае он возвращается в управляемый System.Security.Cryptography.Aes класс.
Можно вручную указать реализацию с помощью вызова UseCustomCryptographicAlgorithms.
Совет
Изменение алгоритмов не влияет на существующие ключи в кольце ключей. Это влияет только на недавно созданные ключи.
Указание пользовательских управляемых алгоритмов
Чтобы указать пользовательские управляемые алгоритмы, создайте экземпляр, указывающий ManagedAuthenticatedEncryptorConfiguration на типы реализации:
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new ManagedAuthenticatedEncryptorConfiguration
{
// A type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// A type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
Как правило, свойства *Type должны указывать на конкретные, экземплярируемые (через открытые методы ctor без параметров) реализации иKeyedHashAlgorithm, хотя системные специальные варианты SymmetricAlgorithm некоторые значения, как typeof(Aes)
и для удобства.
Примечание.
СимметричныйAlgorithm должен иметь длину ключа ≥ 128 бит и размер блока ≥ 64 бита, и он должен поддерживать шифрование в режиме CBC с помощью PKCS #7. KeyedHashAlgorithm должен иметь размер >дайджеста = 128 бит, и он должен поддерживать ключи длины, равной длине хэш-алгоритма. KeyedHashAlgorithm не является строго обязательным для HMAC.
Указание пользовательских алгоритмов Windows CNG
Чтобы указать пользовательский алгоритм CNG Windows с помощью шифрования в режиме CBC с проверкой HMAC, создайте CngCbcAuthenticatedEncryptorConfiguration экземпляр, содержащий алгоритмическую информацию:
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngCbcAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// Passed to BCryptOpenAlgorithmProvider
HashAlgorithm = "SHA256",
HashAlgorithmProvider = null
});
Примечание.
Алгоритм шифра симметричного блока должен иметь длину >ключа = 128 бит, размер >блока = 64 бита, и он должен поддерживать шифрование в режиме CBC с помощью PKCS #7. Хэш-алгоритм должен иметь размер >дайджеста = 128 бит и должен поддерживать открытие с помощью флага BCRYPT_ALG_HANDLE_HMAC_FLAG. Свойства *Provider можно задать значение NULL, чтобы использовать поставщик по умолчанию для указанного алгоритма. Дополнительные сведения см. в документации BCryptOpenAlgorithmProvider .
Чтобы указать пользовательский алгоритм CNG Windows с помощью шифрования режима Galois/Counter с проверкой, создайте CngGcmAuthenticatedEncryptorConfiguration экземпляр, содержащий алгоритмическую информацию:
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngGcmAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
Примечание.
Алгоритм шифра симметричного блока должен иметь длину >ключа = 128 бит, размер блока ровно 128 бит, и он должен поддерживать шифрование GCM. Свойство можно задать EncryptionAlgorithmProvider значение NULL, чтобы использовать поставщик по умолчанию для указанного алгоритма. Дополнительные сведения см. в документации BCryptOpenAlgorithmProvider .
Указание других пользовательских алгоритмов
Хотя и не предоставляется в качестве API первого класса, система защиты данных достаточно расширяема, чтобы разрешить указание почти любого типа алгоритма. Например, можно сохранить все ключи, содержащиеся в аппаратном модуле безопасности (HSM), и предоставить настраиваемую реализацию основных процедур шифрования и расшифровки. Дополнительные сведения см. в статье IAuthenticatedEncryptor о расширяемости криптографии Core.
Сохранение ключей при размещении в контейнере Docker
При размещении в контейнере Docker ключи должны храниться в любом из следующих элементов:
- Папка, которая является томом Docker, который сохраняется за пределами времени существования контейнера, например общий том или том, подключенный к узлу.
- Внешний поставщик, например Хранилище BLOB-объектов Azure (показан в
ProtectKeysWithAzureKeyVault
разделе) или Redis.
Сохранение ключей с помощью Redis
Для хранения ключей следует использовать только версии Redis, поддерживающие сохраняемость данных Redis. Хранилище BLOB-объектов Azure является постоянным и может использоваться для хранения ключей. Дополнительные сведения см. здесь на GitHub.
Ведение журнала DataProtection
Включите Information
ведение журнала уровня DataProtection, чтобы помочь диагностировать проблему. appsettings.json
Следующий файл включает ведение журнала сведений API DataProtection:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.DataProtection": "Information"
}
},
"AllowedHosts": "*"
}
Дополнительные сведения о ведении журнала см. в разделе "Ведение журнала" в .NET Core и ASP.NET Core.
Дополнительные ресурсы
При инициализации системы защиты данных она применяет параметры по умолчанию в зависимости от операционной среды. Эти параметры подходят для приложений, работающих на одном компьютере. Однако есть случаи, когда разработчику может потребоваться изменить параметры по умолчанию:
- Приложение распространяется на несколько компьютеров.
- По соображениям соответствия требованиям.
В этих сценариях система защиты данных предлагает широкий API конфигурации.
Предупреждение
Как и в файлах конфигурации, кольцо ключей защиты данных должно быть защищено с помощью соответствующих разрешений. Вы можете зашифровать ключи по restадресу, но это не препятствует кибератакам создавать новые ключи. Следовательно, это влияет на безопасность вашего приложения. Расположение хранилища, настроенного с помощью Data Protection, должно иметь доступ к самому приложению, аналогично тому, как вы будете защищать файлы конфигурации. Например, если вы решили сохранить кольцо ключей на диске, используйте разрешения файловой системы. Убедитесь, что только в identity том, в каком веб-приложении запущено чтение, запись и создание доступа к этому каталогу. При использовании Хранилище BLOB-объектов Azure только веб-приложение должно иметь возможность читать, записывать или создавать новые записи в хранилище BLOB-объектов и т. д.
Метод AddDataProtection расширения возвращает IDataProtectionBuilderзначение . IDataProtectionBuilder
предоставляет методы расширения, которые можно объединить для настройки параметров защиты данных.
Для расширений защиты данных, используемых в этой статье, требуются следующие пакеты NuGet:
ProtectKeysWithAzureKeyVault
Войдите в Azure с помощью интерфейса командной строки, например:
az login
Чтобы сохранить ключи в Azure Key Vault, настройте систему в ProtectKeysWithAzureKeyVault Startup
классе. blobUriWithSasToken
— полный универсальный код ресурса (URI), в котором должен храниться файл ключа. Универсальный код ресурса (URI) должен содержать маркер SAS в качестве параметра строки запроса:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
}
Для взаимодействия и авторизации приложения с помощью KeyVault необходимо добавить пакет AzureIdentity .
Задайте расположение хранилища кольца ключей (например, PersistKeysToAzureBlobStorage). Необходимо задать расположение, так как вызов ProtectKeysWithAzureKeyVault
реализует параметры автоматической IXmlEncryptor защиты данных, включая расположение хранилища кольца ключей. В предыдущем примере используется Хранилище BLOB-объектов Azure для сохранения кольца ключей. Дополнительные сведения см. в разделе поставщиков хранилища ключей: служба хранилища Azure. Вы также можете сохранить кольцо ключей локально с помощью PersistKeysToFileSystem.
Это keyIdentifier
идентификатор ключа хранилища ключей, используемый для шифрования ключей. Например, ключ, созданный в хранилище ключей с именем dataprotection
в contosokeyvault
идентификаторе ключа https://contosokeyvault.vault.azure.net/keys/dataprotection/
. Предоставьте приложению разрешения Get, Unwrap Key и Wrap Key в хранилище ключей.
ProtectKeysWithAzureKeyVault
Перегрузки:
- ProtectKeysWithAzureKeyVault(IDataProtectionBuilder, Uri, TokenCredential) позволяет использовать URI keyIdentifier и tokenCredential, чтобы система защиты данных могли использовать хранилище ключей.
- ProtectKeysWithAzureKeyVault(IDataProtectionBuilder, String, IKeyEncryptionKeyResolver) позволяет использовать строку keyIdentifier и IKeyEncryptionKeyResolver, чтобы система защиты данных могли использовать хранилище ключей.
Если приложение использует старые пакеты Azure (Microsoft.AspNetCore.DataProtection.AzureStorage и Microsoft.AspNetCore.DataProtection.AzureKeyVault), рекомендуется удалить эти ссылки и обновить их до Azure.Extensions.AspNetCore.DataProtection.Blobs и Azure.Extensions.AspNetCore.DataProtection.Keys. Эти пакеты содержат новые обновления и устраняют некоторые ключевые проблемы с безопасностью и стабильностью старых пакетов.
services.AddDataProtection()
//This blob must already exist before the application is run
.PersistKeysToAzureBlobStorage("<storage account connection string", "<key store container name>", "<key store blob name>")
//Removing this line below for an initial run will ensure the file is created correctly
.ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
Предупреждение
В этой статье показано использование строка подключения. С локальной базой данных пользователь не должен пройти проверку подлинности, но в рабочей среде строка подключения иногда включают пароль для проверки подлинности. Учетные данные владельца ресурса (ROPC) — это риск безопасности, который следует избежать в рабочих базах данных. Рабочие приложения должны использовать самый безопасный поток проверки подлинности. Дополнительные сведения о проверке подлинности для приложений, развернутых в тестовых или рабочих средах, см. в разделе "Безопасные потоки проверки подлинности".
PersistKeysToFileSystem
Чтобы хранить ключи в UNC-ресурсе вместо расположения %LOCALAPPDATA% по умолчанию, настройте систему с помощью PersistKeysToFileSystem:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
}
Предупреждение
Если изменить расположение сохраняемости ключа, система больше не шифрует ключи restпо адресу, так как он не знает, является ли DPAPI соответствующим механизмом шифрования.
PersistKeysToDbContext
Чтобы сохранить ключи в базе данных с помощью EntityFramework, настройте систему с помощью пакета Microsoft.AspNetCore.DataProtection.EntityFrameworkCore :
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToDbContext<DbContext>()
}
Предыдущий код хранит ключи в настроенной базе данных. Контекст базы данных, используемый, должен реализовать IDataProtectionKeyContext
. IDataProtectionKeyContext
предоставляет свойство DataProtectionKeys
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
Это свойство представляет таблицу, в которой хранятся ключи. Создайте таблицу вручную или с помощью DbContext
миграций. Дополнительные сведения см. в разделе DataProtectionKey.
ProtectKeysWith*
Систему можно настроить для защиты ключей, rest вызвав любой из API конфигурации ProtectKeysWith* . Рассмотрим приведенный ниже пример, в котором хранятся ключи в UNC-ресурсе и шифруются эти ключи rest с определенным сертификатом X.509:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(Configuration["Thumbprint"]);
}
Вы можете предоставить сертификат, загруженный X509Certificate2 ProtectKeysWithCertificateиз файла:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", Configuration["Thumbprint"]));
}
Дополнительные примеры и обсуждение встроенных механизмов шифрования ключей см. в разделе "Шифрование Rest ключей".
UnprotectKeysWithAnyCertificate
Вы можете повернуть сертификаты и расшифровать ключи rest с помощью массива X509Certificate2 сертификатов с UnprotectKeysWithAnyCertificateпомощью:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", Configuration["MyPasswordKey"));
.UnprotectKeysWithAnyCertificate(
new X509Certificate2("certificate_old_1.pfx", Configuration["MyPasswordKey_1"]),
new X509Certificate2("certificate_old_2.pfx", Configuration["MyPasswordKey_2"]));
}
SetDefaultKeyLifetime
Чтобы настроить систему для использования времени существования ключа в течение 14 дней вместо 90 дней по умолчанию, используйте SetDefaultKeyLifetimeследующую команду:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
}
SetApplicationName
По умолчанию система защиты данных изолирует приложения друг от друга на основе корневых путей содержимого, даже если они совместно используют один и тот же репозиторий физических ключей. Эта изоляция запрещает приложениям понимать защищенные полезные данные друг друга.
Для совместного использования защищенных полезных данных между приложениями:
- Настройте SetApplicationName в каждом приложении одинаковое значение.
- Используйте ту же версию стека API защиты данных в приложениях. Выполните одно из следующих действий в файлах проектов приложений:
- Ссылка на ту же общую версию платформы с помощью метапакета Microsoft.AspNetCore.App.
- Ссылка на ту же версию пакета защиты данных.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetApplicationName("shared app name");
}
SetApplicationName внутренние наборы DataProtectionOptions.ApplicationDiscriminator. Дополнительные сведения о том, как используется дискриминация, см. в следующих разделах ниже в этой статье:
DisableAutomaticKeyGeneration
Возможно, у вас есть сценарий, в котором приложение не хочет автоматически свернуть ключи (создать новые ключи) по мере истечения срока действия. Одним из примеров этого сценария может быть приложение, настроенное в первичной или вторичной связи, где только основное приложение отвечает за проблемы управления ключами, а вторичные приложения просто имеют представление только для чтения кольца ключей. Вторичные приложения можно настроить для обработки кольца ключей только для чтения, настроив систему с помощью DisableAutomaticKeyGeneration:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.DisableAutomaticKeyGeneration();
}
Изоляция для каждого приложения
Если система защиты данных предоставляется узлом ASP.NET Core, она автоматически изолирует приложения друг от друга, даже если эти приложения выполняются под одной учетной записью рабочего процесса и используют один и тот же главный материал ключей. Это аналогично модификатору IsolateApps из элемента System.Web <machineKey>
.
Механизм изоляции работает путем рассмотрения каждого приложения на локальном компьютере в качестве уникального клиента, таким образом IDataProtector , корневой каталог для любого конкретного приложения автоматически включает идентификатор приложения в качестве дискриминационных (ApplicationDiscriminator). Уникальный идентификатор приложения — это физический путь приложения:
- Для приложений, размещенных в IIS, уникальный идентификатор — это физический путь к приложению IIS. Если приложение развертывается в среде веб-фермы, это значение стабильно предполагает, что среды IIS настроены одинаково на всех компьютерах в веб-ферме.
- Для локальных приложений, работающих на сервереKestrel, уникальный идентификатор — это физический путь к приложению на диске.
Уникальный идентификатор предназначен для выживания сбросов как отдельного приложения, так и самого компьютера.
Этот механизм изоляции предполагает, что приложения не являются вредоносными. Вредоносное приложение всегда может повлиять на любое другое приложение, работающее в той же учетной записи рабочего процесса. В общей среде размещения, в которой приложения являются взаимонадежными, поставщик размещения должен предпринять шаги, чтобы обеспечить изоляцию на уровне ОС между приложениями, включая разделение базовых репозиториев ключей приложений.
Если система защиты данных не предоставляется узлом ASP.NET Core (например, если создать экземпляр с помощью конкретного типа) изоляция приложений DataProtectionProvider
отключена по умолчанию. Если изоляция приложений отключена, все приложения, поддерживаемые одним и тем же материалом ключей, могут совместно использовать полезные данные, если они предоставляют соответствующие цели. Чтобы обеспечить изоляцию приложений в этой среде, вызовите метод SetApplicationName в объекте конфигурации и укажите уникальное имя для каждого приложения.
Защита данных и изоляция приложений
Рассмотрим следующие моменты для изоляции приложений:
При указании нескольких приложений в одном репозитории ключей намерение заключается в том, что приложения используют один и тот же главный материал ключа. Защита данных разрабатывается с предположением, что все приложения, совместно использующие кольцо ключей, могут получить доступ ко всем элементам в этом круге ключей. Уникальный идентификатор приложения используется для изоляции определенных ключей приложения, производных от предоставленных ключей. Он не ожидает, что разрешения на уровне элементов, такие как предоставленные Azure KeyVault, будут использоваться для принудительной дополнительной изоляции. При попытке разрешения уровня элементов возникают ошибки приложения. Если вы не хотите полагаться на встроенную изоляцию приложений, следует использовать отдельные расположения хранилища ключей и не предоставлять общий доступ между приложениями.
Дискриминатор приложения (ApplicationDiscriminator) используется для предоставления разным приложениям общего доступа к одному и тому же материалу главного ключа, но для сохранения их криптографических полезных данных, отличных друг от друга. Чтобы приложения могли читать криптографические полезные данные друг друга, они должны иметь одинаковые дискриминационные приложения, которые можно задать путем вызова
SetApplicationName
.Если приложение скомпрометировано (например, атакой RCE), все основные материалы ключей, доступные для этого приложения, также должны считаться скомпрометированы независимо от состояния защитыrest . Это означает, что если два приложения указываются на один репозиторий, даже если они используют разные дискриминационные приложения, компрометация одного из них функционально эквивалентна компромиссу обоих.
Это "функционально эквивалентно компромиссу обоих" предложений, даже если два приложения используют разные механизмы для защиты ключей.rest Как правило, это не ожидаемая конфигурация. Механизм защиты предназначен для обеспечения защитыrest в случае, если кибератака получает доступ на чтение к репозиторию. Кибератака, которая получает доступ к репозиторию на запись (возможно, из-за того, что они достигли разрешения на выполнение кода в приложении), может вставить вредоносные ключи в хранилище. Система защиты данных намеренно не обеспечивает защиту от кибератаки, который получает доступ на запись в репозиторий ключей.
Если приложения должны оставаться действительно изолированными друг от друга, они должны использовать разные репозитории ключей. Это естественно выходит из определения "изолированных". Приложения не изолированы, если у всех них есть доступ на чтение и запись к хранилищам данных друг друга.
Изменение алгоритмов с помощью UseCryptographicAlgorithms
Стек защиты данных позволяет изменить алгоритм по умолчанию, используемый только что созданными ключами. Самый простой способ сделать это — вызвать из обратного вызова UseCryptographicAlgorithms конфигурации:
services.AddDataProtection()
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
Значение по умолчанию EncryptionAlgorithm — AES-256-CBC, а значение по умолчанию ValidationAlgorithm — HMACSHA256. Политика по умолчанию может быть задана системным администратором с помощью политики на уровне компьютера, но явный вызов UseCryptographicAlgorithms
для переопределения политики по умолчанию.
Вызов UseCryptographicAlgorithms
позволяет указать требуемый алгоритм из предопределенного встроенного списка. Вам не нужно беспокоиться о реализации алгоритма. В приведенном выше сценарии система защиты данных пытается использовать реализацию AES CNG при запуске в Windows. В противном случае он возвращается в управляемый System.Security.Cryptography.Aes класс.
Можно вручную указать реализацию с помощью вызова UseCustomCryptographicAlgorithms.
Совет
Изменение алгоритмов не влияет на существующие ключи в кольце ключей. Это влияет только на недавно созданные ключи.
Указание пользовательских управляемых алгоритмов
Чтобы указать пользовательские управляемые алгоритмы, создайте экземпляр, указывающий ManagedAuthenticatedEncryptorConfiguration на типы реализации:
serviceCollection.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new ManagedAuthenticatedEncryptorConfiguration()
{
// A type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// A type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
Как правило, свойства *Type должны указывать на конкретные, экземплярируемые (через открытые методы ctor без параметров) реализации иKeyedHashAlgorithm, хотя системные специальные варианты SymmetricAlgorithm некоторые значения, как typeof(Aes)
и для удобства.
Примечание.
СимметричныйAlgorithm должен иметь длину ключа ≥ 128 бит и размер блока ≥ 64 бита, и он должен поддерживать шифрование в режиме CBC с помощью PKCS #7. KeyedHashAlgorithm должен иметь размер >дайджеста = 128 бит, и он должен поддерживать ключи длины, равной длине хэш-алгоритма. KeyedHashAlgorithm не является строго обязательным для HMAC.
Указание пользовательских алгоритмов Windows CNG
Чтобы указать пользовательский алгоритм CNG Windows с помощью шифрования в режиме CBC с проверкой HMAC, создайте CngCbcAuthenticatedEncryptorConfiguration экземпляр, содержащий алгоритмическую информацию:
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngCbcAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// Passed to BCryptOpenAlgorithmProvider
HashAlgorithm = "SHA256",
HashAlgorithmProvider = null
});
Примечание.
Алгоритм шифра симметричного блока должен иметь длину >ключа = 128 бит, размер >блока = 64 бита, и он должен поддерживать шифрование в режиме CBC с помощью PKCS #7. Хэш-алгоритм должен иметь размер >дайджеста = 128 бит и должен поддерживать открытие с помощью флага BCRYPT_ALG_HANDLE_HMAC_FLAG. Свойства *Provider можно задать значение NULL, чтобы использовать поставщик по умолчанию для указанного алгоритма. Дополнительные сведения см. в документации BCryptOpenAlgorithmProvider .
Чтобы указать пользовательский алгоритм CNG Windows с помощью шифрования режима Galois/Counter с проверкой, создайте CngGcmAuthenticatedEncryptorConfiguration экземпляр, содержащий алгоритмическую информацию:
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngGcmAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
Примечание.
Алгоритм шифра симметричного блока должен иметь длину >ключа = 128 бит, размер блока ровно 128 бит, и он должен поддерживать шифрование GCM. Свойство можно задать EncryptionAlgorithmProvider значение NULL, чтобы использовать поставщик по умолчанию для указанного алгоритма. Дополнительные сведения см. в документации BCryptOpenAlgorithmProvider .
Указание других пользовательских алгоритмов
Хотя и не предоставляется в качестве API первого класса, система защиты данных достаточно расширяема, чтобы разрешить указание почти любого типа алгоритма. Например, можно сохранить все ключи, содержащиеся в аппаратном модуле безопасности (HSM), и предоставить настраиваемую реализацию основных процедур шифрования и расшифровки. Дополнительные сведения см. в статье IAuthenticatedEncryptor о расширяемости криптографии Core.
Сохранение ключей при размещении в контейнере Docker
При размещении в контейнере Docker ключи должны храниться в любом из следующих элементов:
- Папка, которая является томом Docker, который сохраняется за пределами времени существования контейнера, например общий том или том, подключенный к узлу.
- Внешний поставщик, например Хранилище BLOB-объектов Azure (показан в
ProtectKeysWithAzureKeyVault
разделе) или Redis.
Сохранение ключей с помощью Redis
Для хранения ключей следует использовать только версии Redis, поддерживающие сохраняемость данных Redis. Хранилище BLOB-объектов Azure является постоянным и может использоваться для хранения ключей. Дополнительные сведения см. здесь на GitHub.
Ведение журнала DataProtection
Включите Information
ведение журнала уровня DataProtection, чтобы помочь диагностировать проблему. appsettings.json
Следующий файл включает ведение журнала сведений API DataProtection:
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.DataProtection": "Information"
}
}
}
Дополнительные сведения о ведении журнала см. в разделе "Ведение журнала" в .NET Core и ASP.NET Core.
Дополнительные ресурсы
ASP.NET Core