ASP.NET Core 中的密钥存储提供程序Key storage providers in ASP.NET Core

默认情况下,数据保护系统 使用发现机制 来确定应在何处保存加密密钥。The data protection system employs a discovery mechanism by default to determine where cryptographic keys should be persisted. 开发人员可以重写默认发现机制并手动指定位置。The developer can override the default discovery mechanism and manually specify the location.

警告

如果指定显式密钥持久性位置,数据保护系统将注销静态密钥加密机制,这样密钥就不再静态加密。If you specify an explicit key persistence location, the data protection system deregisters the default key encryption at rest mechanism, so keys are no longer encrypted at rest. 建议你另外指定用于生产部署的 显式密钥加密机制It's recommended that you additionally specify an explicit key encryption mechanism for production deployments.

文件系统File system

若要配置基于文件系统的密钥存储库,请调用 PersistKeysToFileSystem 配置例程,如下所示。To configure a file system-based key repository, call the PersistKeysToFileSystem configuration routine as shown below. 提供指向存储密钥的存储库的 DirectoryInfoProvide a DirectoryInfo pointing to the repository where keys should be stored:

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

DirectoryInfo可以指向本地计算机上的目录,也可以指向网络共享上的文件夹。The DirectoryInfo can point to a directory on the local machine, or it can point to a folder on a network share. 如果指向本地计算机上的目录 (并且方案为仅本地计算机上的应用需要访问权限才能) 使用此存储库,请考虑在 Windows 上使用 WINDOWS DPAPI () 对静态密钥进行加密。If pointing to a directory on the local machine (and the scenario is that only apps on the local machine require access to use this repository), consider using Windows DPAPI (on Windows) to encrypt the keys at rest. 否则,请考虑使用 x.509 证书 来加密静态密钥。Otherwise, consider using an X.509 certificate to encrypt keys at rest.

Azure 存储Azure Storage

AspNetCore. DataProtection包允许将数据保护密钥存储在 Azure Blob 存储中。The Azure.Extensions.AspNetCore.DataProtection.Blobs package allows storing data protection keys in Azure Blob Storage. 可在 web 应用的多个实例之间共享密钥。Keys can be shared across several instances of a web app. 应用可 cookie 在多个服务器之间共享身份验证和 CSRF 保护。Apps can share authentication cookies or CSRF protection across multiple servers.

若要配置 Azure Blob 存储提供程序,请调用 PersistKeysToAzureBlobStorage 重载之一。To configure the Azure Blob Storage provider, call one of the PersistKeysToAzureBlobStorage overloads.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToAzureBlobStorage(new Uri("<blob URI including SAS token>"));
}

如果 web 应用作为 Azure 服务运行,则可以使用连接字符串通过 azure对 azure 存储进行身份验证。If the web app is running as an Azure service, connection string can be used to authenticate to Azure storage by using Azure.Storage.Blobs.

string connectionString = "<connection_string>";
string containerName = "my-key-container";
BlobContainerClient container = new BlobContainerClient(connectionString, containerName);

// optional - provision the container automatically
await container.CreateIfNotExistsAsync();

services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(container, "keys.xml");

备注

可以在 Azure 门户中的 "访问密钥" 部分下找到存储帐户的连接字符串,也可以运行以下 CLI 命令:The connection string to your storage account can be found in the Azure Portal under the "Access Keys" section or by running the following CLI command:

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

RedisRedis

AspNetCore. DataProtection. StackExchangeRedis package 允许在 Redis 缓存中存储数据保护密钥。The Microsoft.AspNetCore.DataProtection.StackExchangeRedis package allows storing data protection keys in a Redis cache. 可在 web 应用的多个实例之间共享密钥。Keys can be shared across several instances of a web app. 应用可 cookie 在多个服务器之间共享身份验证和 CSRF 保护。Apps can share authentication cookies or CSRF protection across multiple servers.

AspNetCore. DataProtection. Redis package 允许在 Redis 缓存中存储数据保护密钥。The Microsoft.AspNetCore.DataProtection.Redis package allows storing data protection keys in a Redis cache. 可在 web 应用的多个实例之间共享密钥。Keys can be shared across several instances of a web app. 应用可 cookie 在多个服务器之间共享身份验证和 CSRF 保护。Apps can share authentication cookies or CSRF protection across multiple servers.

若要在 Redis 上进行配置,请调用 PersistKeysToStackExchangeRedis 重载之一:To configure on Redis, call one of the PersistKeysToStackExchangeRedis overloads:

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

若要在 Redis 上进行配置,请调用 PersistKeysToRedis 重载之一:To configure on Redis, call one of the PersistKeysToRedis overloads:

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

有关详细信息,请参阅下列主题:For more information, see the following topics:

注册表Registry

仅适用于 Windows 部署。Only applies to Windows deployments.

有时应用程序可能没有对文件系统的写访问权限。Sometimes the app might not have write access to the file system. 请考虑一种方案,其中应用作为虚拟服务帐户运行 (如 w3wp.exe 的应用池标识) 。Consider a scenario where an app is running as a virtual service account (such as w3wp.exe 's app pool identity). 在这些情况下,管理员可以设置可由服务帐户标识访问的注册表项。In these cases, the administrator can provision a registry key that's accessible by the service account identity. 调用 PersistKeysToRegistry 扩展方法,如下所示。Call the PersistKeysToRegistry extension method as shown below. 提供一个 RegistryKey ,指向应存储加密密钥的位置:Provide a RegistryKey pointing to the location where cryptographic keys should be stored:

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

重要

建议使用 WINDOWS DPAPI 来加密静态密钥。We recommend using Windows DPAPI to encrypt the keys at rest.

Entity Framework CoreEntity Framework Core

AspNetCore. DataProtection. microsoft.entityframeworkcore包提供了一种机制,用于使用 Entity Framework Core 将数据保护密钥存储到数据库。The Microsoft.AspNetCore.DataProtection.EntityFrameworkCore package provides a mechanism for storing data protection keys to a database using Entity Framework Core. Microsoft.AspNetCore.DataProtection.EntityFrameworkCoreNuGet 包必须添加到项目文件,而不是AspNetCore 元包的一部分。The Microsoft.AspNetCore.DataProtection.EntityFrameworkCore NuGet package must be added to the project file, it's not part of the Microsoft.AspNetCore.App metapackage.

使用此包,可以在 web 应用的多个实例之间共享密钥。With this package, keys can be shared across multiple instances of a web app.

若要配置 EF Core 提供程序,请调用 <TContext> PersistKeysToDbContext方法:To configure the EF Core provider, call the PersistKeysToDbContext<TContext> method:

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 讨论问题中告诉我们。If you would like to see code comments translated to languages other than English, let us know in this GitHub discussion issue.

泛型参数 TContext 必须从 DbContext 继承,并实现 IDataProtectionKeyContextThe generic parameter, TContext, must inherit from DbContext and implement 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 表。Create the DataProtectionKeys table.

包管理器控制台 中执行以下命令 (PMC) 窗口:Execute the following commands in the Package Manager Console (PMC) window:

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

MyKeysContextDbContext 前面的代码示例中定义的。MyKeysContext is the DbContext defined in the preceding code sample. 如果你使用的是 DbContext 其他名称,请将你 DbContext 的名称替换为 MyKeysContextIf you're using a DbContext with a different name, substitute your DbContext name for MyKeysContext.

DataProtectionKeys类/实体采用下表所示的结构。The DataProtectionKeys class/entity adopts the structure shown in the following table.

属性/字段Property/Field CLR 类型CLR Type SQL 类型SQL Type
Id int int,PK, IDENTITY(1,1) ,not nullint, PK, IDENTITY(1,1), not null
FriendlyName string nvarchar(MAX),nullnvarchar(MAX), null
Xml string nvarchar(MAX),nullnvarchar(MAX), null

自定义密钥存储库Custom key repository

如果不适合使用机箱内机制,开发人员可以通过提供自定义 IXmlRepository来指定其自己的密钥持久性机制。If the in-box mechanisms aren't appropriate, the developer can specify their own key persistence mechanism by providing a custom IXmlRepository.