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

本文内容

默认情况下,数据保护系统使用发现机制来确定应在何处保存加密密钥。开发人员可以重写默认的发现机制,并手动指定的位置。

警告

如果指定了显式密钥持久性位置,数据保护系统注销 rest 机制,在默认密钥加密,因此不再静态加密密钥。建议你另外指定用于生产部署的显式密钥加密机制

文件系统File system

若要配置基于文件系统的密钥存储库,请调用PersistKeysToFileSystem配置例程,如下所示。提供指向存储密钥的存储库的DirectoryInfo

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

DirectoryInfo 可以指向本地计算机上的目录,也可以指向网络共享上的文件夹。如果指向本地计算机上的目录(并且方案为仅本地计算机上的应用需要使用此存储库的访问权限),请考虑使用WINDOWS DPAPI (在 windows 上)对静态密钥进行加密。否则,请考虑使用x.509 证书来加密静态密钥。

Azure 存储Azure Storage

AspNetCore. DataProtection. AzureStorage package 允许将数据保护密钥存储在 Azure Blob 存储中。可以在 web 应用的多个实例之间共享密钥。应用可以跨多个服务器共享身份验证 cookie 或 CSRF 保护。

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

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

如果 web 应用作为 Azure 服务运行,则可以使用microsoft.azure.services.appauthentication自动创建身份验证令牌。

  1. var tokenProvider = new AzureServiceTokenProvider();
  2. var token = await tokenProvider.GetAccessTokenAsync("https://storage.azure.com/");
  3. var credentials = new StorageCredentials(new TokenCredential(token));
  4. var storageAccount = new CloudStorageAccount(credentials, "mystorageaccount", "core.windows.net", useHttps: true);
  5. var client = storageAccount.CreateCloudBlobClient();
  6. var container = client.GetContainerReference("my-key-container");
  7. // optional - provision the container automatically
  8. await container.CreateIfNotExistsAsync();
  9. services.AddDataProtection()
  10. .PersistKeysToAzureBlobStorage(container, "keys.xml");

查看有关配置服务到服务身份验证的更多详细信息。

RedisRedis

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

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

若要在 Redis 上进行配置,请调用PersistKeysToStackExchangeRedis重载之一:

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

若要在 Redis 上进行配置,请调用PersistKeysToRedis重载之一:

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

有关详情,请参阅以下主题:

注册表Registry

仅适用于 Windows 部署。

有时应用程序可能没有到文件系统的写访问权限。请考虑一个应用以虚拟服务帐户(例如w3wp.exe的应用程序池标识)运行的方案。在这些情况下,管理员可以预配的服务帐户标识都可访问的注册表项。调用PersistKeysToRegistry扩展方法,如下所示。提供一个RegistryKey ,指向应存储加密密钥的位置:

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

重要

建议使用WINDOWS DPAPI来加密静态密钥。

Entity Framework CoreEntity Framework Core

AspNetCore. DataProtection. microsoft.entityframeworkcore包提供了一种机制,用于使用 Entity Framework Core 将数据保护密钥存储到数据库。必须将 Microsoft.AspNetCore.DataProtection.EntityFrameworkCore NuGet 包添加到项目文件中,它不是AspNetCore 元包的一部分。

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

若要配置 EF Core 提供程序,请调用PersistKeysToDbContext<TContext >方法:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.Configure<CookiePolicyOptions>(options =>
  4. {
  5. options.CheckConsentNeeded = context => true;
  6. options.MinimumSameSitePolicy = SameSiteMode.None;
  7. });
  8. services.AddDbContext<ApplicationDbContext>(options =>
  9. options.UseSqlServer(
  10. Configuration.GetConnectionString("DefaultConnection")));
  11. // Add a DbContext to store your Database Keys
  12. services.AddDbContext<MyKeysContext>(options =>
  13. options.UseSqlServer(
  14. Configuration.GetConnectionString("MyKeysConnection")));
  15. // using Microsoft.AspNetCore.DataProtection;
  16. services.AddDataProtection()
  17. .PersistKeysToDbContext<MyKeysContext>();
  18. services.AddDefaultIdentity<IdentityUser>()
  19. .AddDefaultUI(UIFramework.Bootstrap4)
  20. .AddEntityFrameworkStores<ApplicationDbContext>();
  21. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  22. }

若要查看翻译为非英语语言的代码注释,请在 此 GitHub 讨论问题中告诉我们。

泛型参数 TContext必须继承自DbContext并实现IDataProtectionKeyContext

  1. using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
  2. using Microsoft.EntityFrameworkCore;
  3. using WebApp1.Data;
  4. namespace WebApp1
  5. {
  6. class MyKeysContext : DbContext, IDataProtectionKeyContext
  7. {
  8. // A recommended constructor overload when using EF Core
  9. // with dependency injection.
  10. public MyKeysContext(DbContextOptions<MyKeysContext> options)
  11. : base(options) { }
  12. // This maps to the table that stores keys.
  13. public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
  14. }
  15. }

创建 DataProtectionKeys 表。

在 "包管理器控制台" (PMC)窗口中执行以下命令:

  1. Add-Migration AddDataProtectionKeys -Context MyKeysContext
  2. Update-Database -Context MyKeysContext

在命令行界面中执行以下命令:

  1. dotnet ef migrations add AddDataProtectionKeys --context MyKeysContext
  2. dotnet ef database update --context MyKeysContext

MyKeysContext 是前面的代码示例中定义的 DbContext如果你使用的是其他名称的 DbContext,请将 DbContext 名称替换为 MyKeysContext

DataProtectionKeys 类/实体采用下表所示的结构。

属性/字段CLR 类型SQL 类型
Idintint,PK,not null
FriendlyNamestringnvarchar(MAX),null
Xmlstringnvarchar(MAX),null

自定义密钥存储库Custom key repository

如果不适合使用机箱内机制,开发人员可以通过提供自定义IXmlRepository来指定其自己的密钥持久性机制。