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 来指定自己的密钥保存机制。