初始化后,数据保护系统会基于操作环境应用默认设置。 这些设置适用于在单台计算机上运行的应用。 但是,在某些情况下,开发人员可能要更改默认设置:
- 应用分布在多台计算机上。
- 出于合规性原因。
对于这些情形,数据保护系统提供了丰富的配置 API。
警告
与配置文件类似,应使用适当的权限保护数据保护密钥环。 可以选择静态加密密钥,但这不会阻止网络攻击者创建新密钥。 因此,应用的安全性会受到影响。 使用数据保护配置的存储位置应该将其访问权限限制为应用本身,这与保护配置文件的方式类似。 例如,如果选择将密钥环存储在磁盘上,请使用文件系统权限。 确保用于运行 Web 应用的身份拥有对该目录的读取、写入和创建访问权限。 如果使用 Azure Blob 存储,则只有 Web 应用才应能够在 Blob 存储中读取、写入或创建新条目等。
扩展方法 AddDataProtection 会返回 IDataProtectionBuilder。 IDataProtectionBuilder
会公开扩展方法,可以将这些方法链接在一起来配置数据保护选项。
注意
本文是为一个在 docker 容器中运行的应用编写的。 在 docker 容器中,该应用始终具有相同的路径,因此,也具有相同的应用程序鉴别器。 对于需要在多个环境(例如本地和已部署环境)中运行的应用,必须设置相应环境的默认应用程序鉴别器。 在多个环境中运行应用超出了本文的介绍范围。
本文中使用的数据保护扩展需要以下 NuGet 包:
使用 Azure Key Vault 保护密钥 (ProtectKeysWithAzureKeyVault
)
若要使用开发人员凭据在本地与 Azure Key Vault 交互,请在 Visual Studio 中登录到存储帐户,或使用 Azure CLI 登录。 如果尚未安装 Azure CLI,请参阅 如何安装 Azure CLI。 不使用 Visual Studio 时,可以在 Visual Studio 的开发人员 PowerShell 面板中或命令行界面中执行以下命令:
az login
有关详细信息,请参阅 使用开发人员工具登录到 Azure。
在 Entra 或 Azure 门户中建立密钥保管库时:
将密钥保管库配置为使用 Azure 基于角色的访问控制(RABC)。 如果您未在 Azure 虚拟网络上运行(包括用于本地开发和测试),请确认在网络步骤中,公共访问已启用(已选中)。 启用公共访问仅会公开密钥保管库终结点。 访问仍需要经过身份验证的帐户。
使用“密钥保管库加密用户”角色创建 Azure 托管 Identity(或向计划使用的现有托管 Identity 添加角色)。 将托管Identity分配给托管部署的 Azure 应用服务:设置>Identity>用户分配>添加。
注意
如果你还计划通过授权用户,使用 Azure CLI 或 Visual Studio 的 Azure 服务身份验证,在本地运行应用程序以进行 Blob 访问,请在访问控制 (IAM) 中以密钥保管库加密用户角色添加开发人员 Azure 用户帐户。 若要通过 Visual Studio 使用 Azure CLI,请从开发人员 PowerShell 面板执行
az login
该命令,并按照提示向租户进行身份验证。当密钥加密处于活动状态时,密钥文件中的密钥包括注释“This key is encrypted with Azure Key Vault.”启动应用后,从密钥行末尾的上下文菜单中选择 “查看/编辑 ”命令,以确认密钥是否存在密钥保管库安全性。
(可选)可以启用自动密钥保管库密钥轮换,而无需担心因为密钥保管库密钥过期/轮换而导致的无法用数据保护密钥解密有效负载的问题。 每个生成的数据保护密钥都包含对用于加密密钥的密钥保管库密钥的引用。 只需确保保留过期的密钥保管库密钥,请勿在密钥保管库中删除它们。 此外,在应用的密钥保管库配置中使用无版本密钥标识符,其中没有将密钥 GUID 放置在标识符末尾(例如:
https://contoso.vault.azure.net/keys/data-protection
对两个密钥使用类似的轮换周期,密钥保管库密钥轮换的频率比数据保护密钥更频繁,以确保在数据保护密钥轮换时使用新的密钥保管库密钥。
使用 Azure Key Vault 保护密钥可实现 IXmlEncryptor,从而禁用自动数据保护设置,包括密钥环存储位置。 若要配置 Azure Blob 存储提供程序以将密钥存储在 Blob 存储中,请按照 ASP.NET Core 中的密钥存储提供程序 中的指南作,并在应用中调用其中一个 PersistKeysToAzureBlobStorage 重载。 以下示例使用接受 Blob URI 和令牌凭据 (TokenCredential) 的重载,并依赖于 Azure 托管 Identity 进行基于角色的访问控制 (RBAC)。
若要配置 Azure Key Vault 提供程序,请调用其中一个 ProtectKeysWithAzureKeyVault 重载。 以下示例使用接受密钥标识符和令牌凭据 (TokenCredential) 的重载,在生产环境 (ManagedIdentityCredential) 中依赖托管 Identity 进行 RBAC,或者在开发和测试期间使用 DefaultAzureCredential。 其他重载接受密钥保管库客户端或带有客户端密钥的应用客户端 ID。 有关详细信息,请参阅 ASP.NET Core 中的密钥存储提供程序。
有关 Azure SDK 的 API 和身份验证的详细信息,请参阅 使用 Azure Identity 库向 Azure 服务验证 .NET 应用 ,并使用 Azure 基于角色的访问控制提供对 Key Vault 密钥、证书和机密的访问权限。 有关日志记录指南,请参阅 使用适用于 .NET 的 Azure SDK 进行日志记录:在没有客户端注册的情况下进行日志记录。 对于使用依赖注入的应用,应用可以调用 AddAzureClientsCore,对 enableLogForwarding
传递 true
,以创建和连接日志记录基础结构。
在注册了服务的 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)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}
:Azure 托管 Identity 客户端 ID (GUID)。
{TENANT ID}
:租户 ID。
{APPLICATION NAME}
: SetApplicationName 在数据保护系统中设置此应用的唯一名称。 该值应在应用的各个部署之间保持一致。
{BLOB URI}
:密钥文件的完整 URI。 创建密钥文件时,Azure 存储会生成 URI。 请勿使用 SAS。
{KEY IDENTIFIER}
:用于密钥加密的 Azure Key Vault 密钥标识符。 访问策略允许应用程序使用Get
和Unwrap Key
Wrap Key
权限访问密钥保管库。 在创建密钥后,可以从 Entra 或 Azure 门户中的密钥获取其版本。 如果启用密钥保管库密钥的自动轮换,请确保在应用的密钥保管库配置中使用无版本密钥标识符,其中未在标识符末尾放置任何密钥 GUID(例如: https://contoso.vault.azure.net/keys/data-protection
要使应用能够与 Azure Key Vault 通信和授权自身, Azure.Identity
应用必须引用 NuGet 包 。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
注意
在非生产环境中,前面的示例用于 DefaultAzureCredential 简化身份验证,同时开发部署到 Azure 的应用,方法是将 Azure 托管环境中使用的凭据与本地开发中使用的凭据组合在一起。 有关详细信息,请参阅 使用系统分配的托管标识向 Azure 资源验证 Azure 托管的 .NET 应用。
如果应用使用较旧的 Azure 包(Microsoft.AspNetCore.DataProtection.AzureStorage
以及 Microsoft.AspNetCore.DataProtection.AzureKeyVault
),我们建议 删除 这些引用并升级到 Azure.Extensions.AspNetCore.DataProtection.Blobs
和 Azure.Extensions.AspNetCore.DataProtection.Keys
包。 较新的包解决了关键安全性和稳定性问题。
备用共享访问签名 (SAS) 方法:作为使用托管 Identity 访问 Azure Blob 存储中的密钥 Blob 的替代方法,可以调用接受具有 SAS 令牌的 Blob URI 的 PersistKeysToAzureBlobStorage 重载。 以下示例将继续使用ManagedIdentityCredential(生产)或DefaultAzureCredential(开发和测试)作为其TokenCredential,如前面的示例所示。
builder.Services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{APPLICATION NAME}
: SetApplicationName 在数据保护系统中设置此应用的唯一名称。 该值应在应用的各个部署之间保持一致。
{BLOB URI WITH SAS}
:密钥文件应作为查询字符串参数与 SAS 令牌一起存储的完整 URI。 当你请求用于上传的密钥文件的 SAS 时,Azure 存储会生成 URI。
{KEY IDENTIFIER}
:用于密钥加密的 Azure Key Vault 密钥标识符。 访问策略允许应用程序使用Get
和Unwrap Key
Wrap Key
权限访问密钥保管库。 在创建密钥后,可以从 Entra 或 Azure 门户中的密钥获取其版本。 如果启用密钥保管库密钥的自动轮换,请确保在应用的密钥保管库配置中使用无版本密钥标识符,其中未在标识符末尾放置任何密钥 GUID(例如: https://contoso.vault.azure.net/keys/data-protection
将密钥持久化到文件系统 (PersistKeysToFileSystem
)
若要将密钥存储在 UNC 共享(而不是 %LOCALAPPDATA% 默认位置),请使用 PersistKeysToFileSystem 配置系统:
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
警告
如果更改密钥持久性位置,则系统不再自动对静态密钥进行加密,因为它不知道 DPAPI 是否是适当的加密机制。
在数据库中保留密钥 (PersistKeysToDbContext
)
若要使用 EntityFramework 将密钥存储在数据库中,请使用 Microsoft.AspNetCore.DataProtection.EntityFrameworkCore 包配置系统:
builder.Services.AddDataProtection()
.PersistKeysToDbContext<SampleDbContext>();
上面的代码将密钥存储在配置的数据库中。 所使用的数据库上下文必须实现 IDataProtectionKeyContext
。 IDataProtectionKeyContext
会公开属性 DataProtectionKeys
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
此属性表示在其中存储密钥的表。 手动或使用 DbContext
迁移创建该表。 有关详细信息,请参阅 DataProtectionKey。
保护密钥配置 API (ProtectKeysWith\*
)
可以通过调用任何 ProtectKeysWith\*
配置 API 来配置系统来保护静态密钥。 请考虑以下示例,该示例将密钥存储在 UNC 共享上,并使用特定的 X.509 证书对静态密钥进行加密。
可以通过调用 X509CertificateLoader.LoadCertificateFromFile 将文件中的 X509Certificate2 提供给 ProtectKeysWithCertificate:
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));
下面的代码示例演示如何使用指纹加载证书:
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"]));
下面的代码示例演示如何使用指纹加载证书:
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);
有关内置密钥加密机制的示例和讨论,请参阅 使用 ASP.NET Core 在 Windows 和 Azure 中静态密钥加密。
使用任何证书解锁密钥(UnprotectKeysWithAnyCertificate
)
可以通过将 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 metapackage 引用相同的共享框架版本。
- 引用相同的数据保护包版本。
builder.Services.AddDataProtection()
.SetApplicationName("<sharedApplicationName>");
SetApplicationName 在内部设置 DataProtectionOptions.ApplicationDiscriminator。 出于故障排除目的,可以使用在 Program.cs
中构建 WebApplication 之后放置的以下代码来记录框架分配给鉴别器的值:
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 System.Reflection;
using Microsoft.AspNetCore.DataProtection;
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 主机提供时,它会自动将应用彼此隔离,即使这些应用在相同的工作进程帐户下运行并且使用相同的主密钥材料也是如此。 这类似于 System.Web 的 <machineKey>
元素中的 IsolateApps 修饰符。
隔离机制的工作方式是将本地计算机上的每个应用都视为唯一的租户,因此,任何给定应用的根 IDataProtector 都会自动包含应用 ID 作为鉴别器 (ApplicationDiscriminator)。 应用的唯一 ID 是应用的物理路径:
- 对于在 IIS 中托管的应用,唯一 ID 是应用的 IIS 物理路径。 如果应用在 Web 场环境中进行部署,则此值是稳定的(假定在 Web 场中的所有计算机间都以相似方式配置 IIS 环境)。
- 对于在 Kestrel 服务器上运行的自承载应用,唯一 ID 是应用在磁盘上的物理路径。
唯一标识符的设计目的是在重置后(单个应用和计算机本身)仍保持活动状态。
此隔离机制假定应用不是恶意的。 恶意应用可能会始终影响在相同工作进程帐户下运行的任何其他应用。 在应用互相不受信任的共享宿主环境中,托管提供商应采取措施来确保应用之间的操作系统级隔离,包括分隔应用的基础密钥存储库。
如果数据保护系统不由 ASP.NET Core 主机提供(例如,如果通过 DataProtectionProvider
具体类型进行实例化),则默认情况下会禁用应用隔离。 禁用应用隔离后,只要提供合适的用途,由相同密钥材料支持的所有应用便可以共享有效负载。 若要在此环境中提供应用隔离,请对配置对象调用 SetApplicationName
方法,并为每个应用提供唯一的名称。
数据保护和应用隔离
对于应用隔离,请考虑以下几点:
当多个应用指向相同的密钥存储库时,意图是让这些应用共享相同的主密钥材料。 开发数据保护时,假设共享密钥环的所有应用都可以访问该密钥环中的所有项目。 应用程序唯一标识符用于隔离从密钥环提供密钥派生的应用程序特定密钥。 它不需要项目级权限,例如 Azure KeyVault 提供的用于强制实施额外隔离的权限。 尝试项级权限会生成应用程序错误。 如果你不想依赖内置应用程序隔离,则应使用单独的密钥存储位置,而不是在应用程序之间共享。
应用程序鉴别器 (ApplicationDiscriminator) 用于允许不同的应用共享相同的主密钥材料,但使其加密有效负载彼此不同。 若要使应用能够读取彼此的加密负载,它们必须具有相同的应用程序鉴别器(可通过调用
SetApplicationName
进行设置)。如果应用遭到入侵(例如 RCE 攻击),则应用可访问的所有主密钥材料也必须被视为遭到入侵,而不考虑其静态保护状态。 这意味着,如果两个应用指向相同的存储库,那么即使它们使用不同的应用鉴别器,一个应用遭到入侵在功能上等同于两者都遭到入侵。
即使两个应用使用不同的机制进行静态密钥保护,"在功能上等同于两者的妥协" 的条款仍然成立。 通常,这不是预期配置。 静态保护机制旨在当网络攻击者获得存储库的读取权限时提供保护。 如果网络攻击者获取了存储库写入访问权限(可能是因为他们获得了应用内的代码执行权限),则可以将恶意密钥插入到存储中。 数据保护系统特意不为获得密钥存储库写入访问权限的网络攻击者提供保护。
如果应用需要真正保持相互隔离,则它们应使用不同的密钥存储库。 这自然不属于“隔离”的定义。 如果应用全部对彼此的数据存储具有读取和写入访问权限,则应用未隔离。
使用 UseCryptographicAlgorithms
更改算法
数据保护堆栈允许更改新生成的密钥所使用的默认算法。 执行此操作的最简单方法是从配置回调调用 UseCryptographicAlgorithms:
builder.Services.AddDataProtection()
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
默认 EncryptionAlgorithm 为 AES-256-CBC,默认 ValidationAlgorithm 为 HMACSHA256。 系统管理员可以通过计算机范围策略设置默认策略,但是对 UseCryptographicAlgorithms
的显式调用会替代默认策略。
通过调用 UseCryptographicAlgorithms
可以从预定义内置列表指定所需算法。 无需担心算法的实现。 在以上方案中,如果在 Windows 上运行,则数据保护系统会尝试使用 AES 的 CNG 实现。 否则,它会回退到托管 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 属性必须指向 SymmetricAlgorithm 和 KeyedHashAlgorithm 的可实例化(通过公共无参数构造函数)具体实现,不过为了方便起见,系统对一些值(如 typeof(Aes)
)进行了特殊处理。
注意
SymmetricAlgorithm 必须具有 ≥ 128 位的密钥长度和 ≥ 64 位的块大小,并且必须支持具有 PKCS #7 填充的 CBC 模式加密。 KeyedHashAlgorithm 的摘要大小必须为 >= 128 位,并且它必须支持长度等于哈希算法摘要长度的密钥。 KeyedHashAlgorithm 并不严格要求是 HMAC。
指定自定义 Windows CNG 算法
若要使用具有 HMAC 验证的 CBC 模式加密来指定自定义 Windows CNG 算法,请创建包含算法信息的 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
});
注意
symmetric 分组加密算法必须具有 >= 128 位的密钥长度和 >= 64 位的块大小,并且必须支持具有 PKCS #7 填充的 CBC 模式加密。 哈希算法的摘要大小必须为 >= 128 位,并且必须支持使用 BCRYPT_ALG_HANDLE_HMAC_FLAG 标志打开。 *Provider 属性可以设置为 null,以将默认提供程序用于指定算法。 有关详细新,请参阅 BCryptOpenAlgorithmProvider 文档。
若要使用具有验证的 Galois/Counter 模式加密来指定自定义 Windows CNG 算法,请创建包含算法信息的 CngGcmAuthenticatedEncryptorConfiguration 实例:
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngGcmAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
注意
symmetric 分组加密算法必须具有 >= 128 位的密钥长度和恰好 128 位的块大小,并且必须支持 GCM 加密。 可以将 EncryptionAlgorithmProvider 属性设置为 null,以将默认提供程序用于指定算法。 有关详细新,请参阅 BCryptOpenAlgorithmProvider 文档。
指定其他自定义算法
尽管不是作为第一类 API 公开,但数据保护系统的扩展性足以允许指定几乎任何类型的算法。 例如,可以保留硬件安全模块 (HSM) 中包含的所有密钥,并提供核心加密和解密例程的自定义实现。 有关详细信息,请参阅核心加密扩展性中的 IAuthenticatedEncryptor。
在 Docker 容器中托管时保持密钥
在 Docker 容器中托管时,应在以下任一项中维护密钥:
- 文件夹,它是在容器生存期之外保持的 Docker 卷,如共享卷或主机装载的卷。
- 外部提供程序,如 Azure Blob 存储(在
ProtectKeysWithAzureKeyVault
部分中显示)或 Redis。
使用 Redis 保持密钥
只应使用支持 Redis 数据持久性的 Redis 版本来存储密钥。 Azure Blob 存储是持久性的,可用于存储密钥。 有关详细信息,请参阅此 GitHub 问题。
伐木业
启用Information
或较低的日志记录级别来诊断问题。 以下 appsettings.json
文件会启用数据保护 API 的信息日志记录:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.DataProtection": "Information"
}
},
"AllowedHosts": "*"
}
有关日志记录的详细信息,请参阅 .NET Core 和 ASP.NET Core 中的日志记录。
其他资源
初始化后,数据保护系统会基于操作环境应用默认设置。 这些设置适用于在单台计算机上运行的应用。 但是,在某些情况下,开发人员可能要更改默认设置:
- 应用分布在多台计算机上。
- 出于合规性原因。
对于这些情形,数据保护系统提供了丰富的配置 API。
警告
与配置文件类似,应使用适当的权限保护数据保护密钥环。 可以选择静态加密密钥,但这不会阻止网络攻击者创建新密钥。 因此,应用的安全性会受到影响。 使用数据保护配置的存储位置应该将其访问权限限制为应用本身,这与保护配置文件的方式类似。 例如,如果选择将密钥环存储在磁盘上,请使用文件系统权限。 确保用于运行 Web 应用的身份拥有对该目录的读取、写入和创建访问权限。 如果使用 Azure Blob 存储,则只有 Web 应用才能够在 Blob 存储中读取、写入或创建新条目。
扩展方法 AddDataProtection 返回一个 IDataProtectionBuilder,它公开了可以链接在一起以配置数据保护选项的扩展方法。
本文中使用的数据保护扩展需要以下 NuGet 包:
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
使用 Azure Key Vault 保护密钥 (ProtectKeysWithAzureKeyVault
)
若要使用开发人员凭据在本地与 Azure Key Vault 交互,请在 Visual Studio 中登录到存储帐户,或使用 Azure CLI 登录。 如果尚未安装 Azure CLI,请参阅 如何安装 Azure CLI。 不使用 Visual Studio 时,可以在 Visual Studio 的开发人员 PowerShell 面板中或命令行界面中执行以下命令:
az login
有关详细信息,请参阅 使用开发人员工具登录到 Azure。
在 Entra 或 Azure 门户中建立密钥保管库时:
将密钥保管库配置为使用 Azure 基于角色的访问控制(RABC)。 如果您未在 Azure 虚拟网络上运行(包括用于本地开发和测试),请确认在网络步骤中,公共访问已启用(已选中)。 启用公共访问仅会公开密钥保管库终结点。 访问仍需要经过身份验证的帐户。
使用“密钥保管库加密用户”角色创建 Azure 托管 Identity(或向计划使用的现有托管 Identity 添加角色)。 将托管Identity分配给托管部署的 Azure 应用服务:设置>Identity>用户分配>添加。
注意
如果你还计划通过授权用户,使用 Azure CLI 或 Visual Studio 的 Azure 服务身份验证,在本地运行应用程序以进行 Blob 访问,请在访问控制 (IAM) 中以密钥保管库加密用户角色添加开发人员 Azure 用户帐户。 若要通过 Visual Studio 使用 Azure CLI,请从开发人员 PowerShell 面板执行
az login
该命令,并按照提示向租户进行身份验证。当密钥加密处于活动状态时,密钥文件中的密钥包括注释“This key is encrypted with Azure Key Vault.”启动应用后,从密钥行末尾的上下文菜单中选择 “查看/编辑 ”命令,以确认密钥是否存在密钥保管库安全性。
(可选)可以启用自动密钥保管库密钥轮换,而无需担心因为密钥保管库密钥过期/轮换而导致的无法用数据保护密钥解密有效负载的问题。 每个生成的数据保护密钥都包含对用于加密密钥的密钥保管库密钥的引用。 只需确保保留过期的密钥保管库密钥,请勿在密钥保管库中删除它们。 此外,在应用的密钥保管库配置中使用无版本密钥标识符,其中没有将密钥 GUID 放置在标识符末尾(例如:
https://contoso.vault.azure.net/keys/data-protection
对两个密钥使用类似的轮换周期,密钥保管库密钥轮换的频率比数据保护密钥更频繁,以确保在数据保护密钥轮换时使用新的密钥保管库密钥。
使用 Azure Key Vault 保护密钥可实现 IXmlEncryptor,从而禁用自动数据保护设置,包括密钥环存储位置。 若要配置 Azure Blob 存储提供程序以将密钥存储在 Blob 存储中,请按照 ASP.NET Core 中的密钥存储提供程序 中的指南作,并在应用中调用其中一个 PersistKeysToAzureBlobStorage 重载。 以下示例使用接受 Blob URI 和令牌凭据 (TokenCredential) 的重载,并依赖于 Azure 托管 Identity 进行基于角色的访问控制 (RBAC)。
若要配置 Azure Key Vault 提供程序,请调用其中一个 ProtectKeysWithAzureKeyVault 重载。 以下示例使用接受密钥标识符和令牌凭据 (TokenCredential) 的重载,在生产环境 (ManagedIdentityCredential) 中依赖托管 Identity 进行 RBAC,或者在开发和测试期间使用 DefaultAzureCredential。 其他重载接受密钥保管库客户端或带有客户端密钥的应用客户端 ID。 有关详细信息,请参阅 ASP.NET Core 中的密钥存储提供程序。
有关 Azure SDK 的 API 和身份验证的详细信息,请参阅 使用 Azure Identity 库向 Azure 服务验证 .NET 应用 ,并使用 Azure 基于角色的访问控制提供对 Key Vault 密钥、证书和机密的访问权限。 有关日志记录指南,请参阅 使用适用于 .NET 的 Azure SDK 进行日志记录:在没有客户端注册的情况下进行日志记录。 对于使用依赖注入的应用,应用可以调用 AddAzureClientsCore,对 enableLogForwarding
传递 true
,以创建和连接日志记录基础结构。
在注册了服务的 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);
}
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}
:Azure 托管 Identity 客户端 ID (GUID)。
{TENANT ID}
:租户 ID。
{APPLICATION NAME}
: SetApplicationName 在数据保护系统中设置此应用的唯一名称。 该值应在应用的各个部署之间保持一致。
{BLOB URI}
:密钥文件的完整 URI。 创建密钥文件时,Azure 存储会生成 URI。 请勿使用 SAS。
{KEY IDENTIFIER}
:用于密钥加密的 Azure Key Vault 密钥标识符。 访问策略允许应用程序使用Get
和Unwrap Key
Wrap Key
权限访问密钥保管库。 在创建密钥后,可以从 Entra 或 Azure 门户中的密钥获取其版本。 如果启用密钥保管库密钥的自动轮换,请确保在应用的密钥保管库配置中使用无版本密钥标识符,其中未在标识符末尾放置任何密钥 GUID(例如: https://contoso.vault.azure.net/keys/data-protection
要使应用能够与 Azure Key Vault 通信和授权自身, Azure.Identity
应用必须引用 NuGet 包 。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
注意
在非生产环境中,前面的示例用于 DefaultAzureCredential 简化身份验证,同时开发部署到 Azure 的应用,方法是将 Azure 托管环境中使用的凭据与本地开发中使用的凭据组合在一起。 有关详细信息,请参阅 使用系统分配的托管标识向 Azure 资源验证 Azure 托管的 .NET 应用。
如果应用使用较旧的 Azure 包(Microsoft.AspNetCore.DataProtection.AzureStorage
以及 Microsoft.AspNetCore.DataProtection.AzureKeyVault
),我们建议 删除 这些引用并升级到 Azure.Extensions.AspNetCore.DataProtection.Blobs
和 Azure.Extensions.AspNetCore.DataProtection.Keys
包。 较新的包解决了关键安全性和稳定性问题。
备用共享访问签名 (SAS) 方法:作为使用托管 Identity 访问 Azure Blob 存储中的密钥 Blob 的替代方法,可以调用接受具有 SAS 令牌的 Blob URI 的 PersistKeysToAzureBlobStorage 重载。 以下示例将继续使用ManagedIdentityCredential(生产)或DefaultAzureCredential(开发和测试)作为其TokenCredential,如前面的示例所示。
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{APPLICATION NAME}
: SetApplicationName 在数据保护系统中设置此应用的唯一名称。 该值应在应用的各个部署之间保持一致。
{BLOB URI WITH SAS}
:密钥文件应作为查询字符串参数与 SAS 令牌一起存储的完整 URI。 当你请求用于上传的密钥文件的 SAS 时,Azure 存储会生成 URI。
{KEY IDENTIFIER}
:用于密钥加密的 Azure Key Vault 密钥标识符。 访问策略允许应用程序使用Get
和Unwrap Key
Wrap Key
权限访问密钥保管库。 在创建密钥后,可以从 Entra 或 Azure 门户中的密钥获取其版本。 如果启用密钥保管库密钥的自动轮换,请确保在应用的密钥保管库配置中使用无版本密钥标识符,其中未在标识符末尾放置任何密钥 GUID(例如: https://contoso.vault.azure.net/keys/data-protection
将密钥持久化到文件系统 (PersistKeysToFileSystem
)
若要将密钥存储在 UNC 共享(而不是 %LOCALAPPDATA% 默认位置),请使用 PersistKeysToFileSystem 配置系统:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
}
警告
如果更改密钥持久性位置,则系统不再自动对静态密钥进行加密,因为它不知道 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。
保护密钥配置 API (ProtectKeysWith\*
)
可以通过调用任何 ProtectKeysWith\*
配置 API 来配置系统来保护静态密钥。 请考虑以下示例,该示例将密钥存储在 UNC 共享上,并使用特定的 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"]));
}
有关内置密钥加密机制的更多示例和讨论,请参阅 使用 ASP.NET Core 在 Windows 和 Azure 中静态密钥加密。
使用任何证书解锁密钥(UnprotectKeysWithAnyCertificate
)
可以通过将 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 metapackage 引用相同的共享框架版本。
- 引用相同的数据保护包版本。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}");
}
SetApplicationName 在内部设置 DataProtectionOptions.ApplicationDiscriminator。 有关如何使用鉴别器的详细信息,请参阅本文后面的以下部分:
禁用自动密钥生成(DisableAutomaticKeyGeneration
)
你可能会遇到这样的情况:不希望应用自动滚动更新密钥(创建新密钥),因为它们接近过期。 这种情况的一个示例可能是采用主/辅助关系进行设置的应用,其中只有主应用才负责密钥管理问题,而辅助应用只是具有密钥环的只读视图。 可以通过使用 DisableAutomaticKeyGeneration 配置系统,将辅助应用配置为将密钥环视为只读:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.DisableAutomaticKeyGeneration();
}
按应用程序隔离
当数据保护系统由 ASP.NET Core 主机提供时,它会自动将应用彼此隔离,即使这些应用在相同的工作进程帐户下运行并且使用相同的主密钥材料也是如此。 这类似于 System.Web 的 <machineKey>
元素中的 IsolateApps 修饰符。
隔离机制的工作方式是将本地计算机上的每个应用都视为唯一的租户,因此,任何给定应用的根 IDataProtector 都会自动包含应用 ID 作为鉴别器 (ApplicationDiscriminator)。 应用的唯一 ID 是应用的物理路径:
- 对于在 IIS 中托管的应用,唯一 ID 是应用的 IIS 物理路径。 如果应用在 Web 场环境中进行部署,则此值是稳定的(假定在 Web 场中的所有计算机间都以相似方式配置 IIS 环境)。
- 对于在 Kestrel 服务器上运行的自承载应用,唯一 ID 是应用在磁盘上的物理路径。
唯一标识符的设计目的是在重置后(单个应用和计算机本身)仍保持活动状态。
此隔离机制假定应用不是恶意的。 恶意应用可能会始终影响在相同工作进程帐户下运行的任何其他应用。 在应用互相不受信任的共享宿主环境中,托管提供商应采取措施来确保应用之间的操作系统级隔离,包括分隔应用的基础密钥存储库。
如果数据保护系统不由 ASP.NET Core 主机提供(例如,如果通过 DataProtectionProvider
具体类型进行实例化),则默认情况下会禁用应用隔离。 禁用应用隔离后,只要提供合适的用途,由相同密钥材料支持的所有应用便可以共享有效负载。 若要在此环境中提供应用隔离,请对配置对象调用 SetApplicationName 方法,并为每个应用提供唯一的名称。
数据保护和应用隔离
对于应用隔离,请考虑以下几点:
当多个应用指向相同的密钥存储库时,意图是让这些应用共享相同的主密钥材料。 开发数据保护时,假设共享密钥环的所有应用都可以访问该密钥环中的所有项目。 应用程序唯一标识符用于隔离从密钥环提供密钥派生的应用程序特定密钥。 它不需要项目级权限,例如 Azure KeyVault 提供的用于强制实施额外隔离的权限。 尝试项级权限会生成应用程序错误。 如果你不想依赖内置应用程序隔离,则应使用单独的密钥存储位置,而不是在应用程序之间共享。
应用程序鉴别器 (ApplicationDiscriminator) 用于允许不同的应用共享相同的主密钥材料,但使其加密有效负载彼此不同。 若要使应用能够读取彼此的加密负载,它们必须具有相同的应用程序鉴别器(可通过调用
SetApplicationName
进行设置)。如果应用遭到入侵(例如 RCE 攻击),则应用可访问的所有主密钥材料也必须被视为遭到入侵,而不考虑其静态保护状态。 这意味着,如果两个应用指向相同的存储库,那么即使它们使用不同的应用鉴别器,一个应用遭到入侵在功能上等同于两者都遭到入侵。
即使两个应用使用不同的机制进行静态密钥保护,"在功能上等同于两者的妥协" 的条款仍然成立。 通常,这不是预期配置。 静态保护机制旨在当网络攻击者获得存储库的读取权限时提供保护。 如果网络攻击者获取了存储库写入访问权限(可能是因为他们获得了应用内的代码执行权限),则可以将恶意密钥插入到存储中。 数据保护系统特意不为获得密钥存储库写入访问权限的网络攻击者提供保护。
如果应用需要真正保持相互隔离,则它们应使用不同的密钥存储库。 这自然不属于“隔离”的定义。 如果应用全部对彼此的数据存储具有读取和写入访问权限,则应用未隔离。
使用 UseCryptographicAlgorithms
更改算法
数据保护堆栈允许更改新生成的密钥所使用的默认算法。 执行此操作的最简单方法是从配置回调调用 UseCryptographicAlgorithms:
services.AddDataProtection()
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
默认 EncryptionAlgorithm 为 AES-256-CBC,默认 ValidationAlgorithm 为 HMACSHA256。 系统管理员可以通过计算机范围策略设置默认策略,但是对 UseCryptographicAlgorithms
的显式调用会替代默认策略。
通过调用 UseCryptographicAlgorithms
可以从预定义内置列表指定所需算法。 无需担心算法的实现。 在以上方案中,如果在 Windows 上运行,则数据保护系统会尝试使用 AES 的 CNG 实现。 否则,它会回退到托管 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 属性必须指向 SymmetricAlgorithm 和 KeyedHashAlgorithm 的可实例化(通过公共无参数构造函数)具体实现,不过为了方便起见,系统对一些值(如 typeof(Aes)
)进行了特殊处理。
注意
SymmetricAlgorithm 必须具有 ≥ 128 位的密钥长度和 ≥ 64 位的块大小,并且必须支持具有 PKCS #7 填充的 CBC 模式加密。 KeyedHashAlgorithm 的摘要大小必须为 >= 128 位,并且它必须支持长度等于哈希算法摘要长度的密钥。 KeyedHashAlgorithm 并不严格要求是 HMAC。
指定自定义 Windows CNG 算法
若要使用具有 HMAC 验证的 CBC 模式加密来指定自定义 Windows CNG 算法,请创建包含算法信息的 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
});
注意
symmetric 分组加密算法必须具有 >= 128 位的密钥长度和 >= 64 位的块大小,并且必须支持具有 PKCS #7 填充的 CBC 模式加密。 哈希算法的摘要大小必须为 >= 128 位,并且必须支持使用 BCRYPT_ALG_HANDLE_HMAC_FLAG 标志打开。 *Provider 属性可以设置为 null,以将默认提供程序用于指定算法。 有关详细新,请参阅 BCryptOpenAlgorithmProvider 文档。
若要使用具有验证的 Galois/Counter 模式加密来指定自定义 Windows CNG 算法,请创建包含算法信息的 CngGcmAuthenticatedEncryptorConfiguration 实例:
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngGcmAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
注意
symmetric 分组加密算法必须具有 >= 128 位的密钥长度和恰好 128 位的块大小,并且必须支持 GCM 加密。 可以将 EncryptionAlgorithmProvider 属性设置为 null,以将默认提供程序用于指定算法。 有关详细新,请参阅 BCryptOpenAlgorithmProvider 文档。
指定其他自定义算法
尽管不是作为第一类 API 公开,但数据保护系统的扩展性足以允许指定几乎任何类型的算法。 例如,可以保留硬件安全模块 (HSM) 中包含的所有密钥,并提供核心加密和解密例程的自定义实现。 有关详细信息,请参阅核心加密扩展性中的 IAuthenticatedEncryptor。
在 Docker 容器中托管时保持密钥
在 Docker 容器中托管时,应在以下任一项中维护密钥:
- 文件夹,它是在容器生存期之外保持的 Docker 卷,如共享卷或主机装载的卷。
- 外部提供程序,如 Azure Blob 存储(显示在“使用 Azure Key Vault 保护密钥”
ProtectKeysWithAzureKeyVault
部分)或 Redis。
使用 Redis 保持密钥
只应使用支持 Redis 数据持久性的 Redis 版本来存储密钥。 Azure Blob 存储是持久性的,可用于存储密钥。 有关详细信息,请参阅此 GitHub 问题。
伐木业
启用Information
或较低的日志记录级别来诊断问题。 以下 appsettings.json
文件会启用数据保护 API 的信息日志记录:
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.DataProtection": "Information"
}
}
}
有关日志记录的详细信息,请参阅 .NET Core 和 ASP.NET Core 中的日志记录。