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 包允许将数据保护密钥存储在 Azure Blob 存储中。 可以在 Web 应用的多个实例之间共享密钥。 应用可以跨多个服务器共享身份验证 cookie 或 CSRF 保护。

若要配置 Azure Blob 存储提供程序,请调用 PersistKeysToAzureBlobStorage 重载之一。

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

如果 Web 应用作为 Azure 服务运行,则可以使用连接字符串通过 Azure.Storage.Blobs 向 Azure 存储进行身份验证。

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

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

BlobClient blobClient = container.GetBlobClient(blobName);

services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(blobClient);

注意

存储帐户的连接字符串可以在 Azure 门户的“访问密钥”部分下找到,也可以通过运行以下 CLI 命令找到:

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

Redis

Microsoft.AspNetCore.DataProtection.StackExchangeRedis 包允许将数据保护密钥存储在 Redis 缓存中。 可以在 Web 应用的多个实例之间共享密钥。 应用可以跨多个服务器共享身份验证 cookie 或 CSRF 保护。

Microsoft.AspNetCore.DataProtection.Redis 包允许将数据保护密钥存储在 Redis 缓存中。 可以在 Web 应用的多个实例之间共享密钥。 应用可以跨多个服务器共享身份验证 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 元包的一部分。

使用此包,可以在 Web 应用的多个实例之间共享密钥。

要配置 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)、null
Xml string nvarchar(MAX)、null

自定义密钥存储库

如果内置机制不适用,开发人员可以通过提供自定义 IXmlRepository 来指定自己的密钥保存机制。