共用方式為


ASP.NET Core 中的金鑰儲存體提供者

資料保護系統預設會採用探索機制來判斷密碼編譯金鑰應保存的位置。 開發人員可以覆寫預設探索機制,並手動指定位置。

警告

如果您指定了明確的金鑰持續性位置,數據保護系統會取消註冊預設的密鑰靜態加密機制,因此密鑰不再以靜態方式加密。 建議您另外為生產部署指定明確的金鑰加密機制

檔案系統

若要設定檔案系統型金鑰存放庫,請呼叫 PersistKeysToFileSystem 組態常式,如下所示。 請提供指向應存放金鑰的儲存庫的 DirectoryInfo

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

DirectoryInfo 可以指向本機電腦上的目錄,也可以指向網路共用上的資料夾。 如果指向本地機器上的目錄(而場景是只有本地機器上的應用程式需要存取此存放庫),請考慮使用 Windows DPAPI 對靜態密鑰進行加密。 否則,請考慮使用 X.509 憑證 來加密待用密鑰。

Azure 儲存體

Azure.Extensions.AspNetCore.DataProtection.Blobs NuGet 套件提供 API,以將數據保護金鑰儲存在 Azure Blob 記憶體中。 金鑰可以在 Web 應用程式的數個執行個體之間共用。 應用程式可以跨多部伺服器共用驗證 cookies 或 CSRF 保護。

注意

如需將套件新增至 .NET 應用程式的指引,請參閱 套件取用工作流程 (NuGet 文件) 下的安裝和管理套件相關文章。 在 NuGet.org確認正確的套件版本。

若要使用開發人員認證在 本機與 Azure Key Vault 互動,請在 Visual Studio 中登入您的記憶體帳戶,或使用 Azure CLI 登入。 如果您尚未安裝 Azure CLI,請參閱 如何安裝 Azure CLI。 當您不使用 Visual Studio 時,您可以在 Visual Studio 的開發人員 PowerShell 面板或命令殼層中執行下列命令:

az login

如需詳細資訊,請參閱 使用開發人員工具登入 Azure

設定 Azure Blob 記憶體以維護資料保護金鑰:

  • 建立 Azure 儲存體帳戶。

  • 建立容器來保存數據保護金鑰檔案。

  • 我們建議使用 Azure 受控 Identity 和角色型存取控制(RBAC)來存取金鑰儲存 Blob。 您不需要建立金鑰檔案,並將它上傳至記憶體帳戶的容器。 架構會為您建立檔案。 若要檢查金鑰檔案的內容,請在入口網站中金鑰列結尾使用內容功能表的檢視/編輯命令。

注意

如果您打算將 Blob URI 搭配共用存取簽章 (SAS) 使用,而不是受控, Identity請使用文字編輯器在本機電腦上建立 XML 金鑰檔案:

<?xml version="1.0" encoding="utf-8"?>
<repository>
</repository>

將金鑰檔案上傳至記憶體帳戶的容器。 使用內容功能表的檢視/編輯命令來確認位於入口網站的鍵列末尾的 Blob 包含上述內容。 藉由手動建立檔案,您就可以從入口網站取得具有 SAS 的 Blob URI,以在稍後的步驟中設定應用程式。

  • 建立 Azure 受控 Identity 角色(或將角色新增至您打算使用的現有受控 Identity 角色),並搭配 記憶體 Blob 數據參與者 角色。 將受控Identity指派給裝載部署的 Azure App Service:設定>Identity>使用者指派>新增

    注意

    如果您也打算在本機使用授權使用者來執行應用程式以進行 Blob 存取,並使用 Azure CLI 或 Visual Studio 的 Azure 服務驗證,請在 訪問控制(IAM) 中新增您的開發人員 Azure 使用者帳戶,並賦予 儲存體 Blob 資料貢獻者 角色。 如果您想要透過Visual Studio使用 Azure CLI,請從開發人員 PowerShell 面板執行 az login 命令,並遵循提示向租用戶進行驗證。

若要設定 Azure Blob 記憶體提供者,請呼叫應用程式中的 PersistKeysToAzureBlobStorage 其中一個多載。 下列範例會使用接受 Blob URI 和令牌認證的多載TokenCredential,依賴 Azure 受控Identity 進行角色為基礎的存取控制(RBAC)。

其他重載根據以下內容:

  • Blob URI 和記憶體共用金鑰認證 (StorageSharedKeyCredential)。
  • 具有共用存取簽章的 Blob URI(SAS)。
  • 連接字串、容器名稱和 Blob 名稱。
  • Blob 用戶端 (BlobClient)。

如需 Azure SDK API 和驗證的詳細資訊,請參閱 使用 Azure 連結庫向 Azure Identity 服務驗證 .NET 應用程式。 如需記錄指引,請參閱 使用適用於 .NET 的 Azure SDK 進行記錄:不使用客戶端註冊進行記錄。 對於使用相依性注入的應用程式,應用程式可以呼叫 AddAzureClientsCore,並將 true 作為 enableLogForwarding 傳遞,以建立和配置日誌基礎架構。

在註冊服務的檔案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);

{MANAGED IDENTITY CLIENT ID}:Azure 託管的 Identity 客戶端識別碼 (GUID)。

{TENANT ID}:租使用者標識碼。

{APPLICATION NAME}SetApplicationName 設定資料保護系統中此應用程式的唯一名稱。 應用程式部署間的值應保持一致。

{BLOB URI}:金鑰檔案的完整 URI。 當您建立密鑰檔案時,Azure 記憶體會產生 URI。 請勿使用 SAS。

替代的共用存取簽章 (SAS) 方法:作為使用受控 Identity 存取 Azure Blob 儲存器中密鑰 Blob 的替代方法,您可以呼叫 PersistKeysToAzureBlobStorage 接受具有 SAS 令牌之 Blob URI 的多載:

builder.Services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"));

Startup.ConfigureServices 中:

TokenCredential? credential;

if (_env.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);

{MANAGED IDENTITY CLIENT ID}:Azure 託管的 Identity 客戶端識別碼 (GUID)。

{TENANT ID}:租使用者標識碼。

{APPLICATION NAME}SetApplicationName 設定資料保護系統中此應用程式的唯一名稱。 應用程式部署間的值應保持一致。

{BLOB URI}:金鑰檔案的完整 URI。 當您建立密鑰檔案時,Azure 記憶體會產生 URI。 請勿使用 SAS。

範例:

https://contoso.blob.core.windows.net/data-protection/keys.xml

替代的共用存取簽章 (SAS) 方法:作為使用受控 Identity 存取 Azure Blob 儲存器中密鑰 Blob 的替代方法,您可以呼叫 PersistKeysToAzureBlobStorage 接受具有 SAS 令牌之 Blob URI 的多載:

services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"));

{APPLICATION NAME}SetApplicationName 設定資料保護系統中此應用程式的唯一名稱。 應用程式部署間的值應保持一致。

{BLOB URI WITH SAS}:金鑰檔案應存放的完整 URI,其中包含作為查詢字串參數的 SAS 令牌。 當您要求為上傳的密鑰檔案生成 SAS 時,Azure 儲存會產生 URI。 在下列範例中,容器名稱為 data-protection,而記憶體帳戶名稱為 contoso。 金鑰檔案名名 。 keys.xml 共用存取簽章 (SAS) 查詢字串位於 URI ({SHARED ACCESS SIGNATURE} 佔位元) 的結尾。

範例:

https://contoso.blob.core.windows.net/data-protection/keys.xml{SHARED ACCESS SIGNATURE}

如果 Web 應用程式是以 Azure 服務的形式執行,則連接字串可用來使用 BlobContainerClient向 Azure 記憶體進行驗證,如下列範例所示。

警告

本文說明如何使用 連接字串。 使用本機資料庫時,使用者不需要經過驗證,但在生產環境中,連接字串 有時會包含要驗證的密碼。 資源擁有者密碼認證 (ROPC) 是生產資料庫中應避免的安全性風險。 實際執行應用程式應該使用可用的最安全驗證流程。 如需部署至測試或生產環境之應用程式驗證的詳細資訊,請參閱 保護驗證流程

如果容器不存在,選擇性調用CreateIfNotExistsAsync 會自動布建該容器。

您可以在 Entra 或 Azure 入口網站的 [存取金鑰] 區段下取得儲存體帳戶的連接字串({CONNECTION STRING} 佔位符),或藉由執行下列 Azure CLI 命令來取得。

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

在註冊服務的檔案Program中:

string connectionString = "{CONNECTION STRING}";
string containerName = "{CONTAINER NAME}";
string blobName = "keys.xml";
var container = new BlobContainerClient(connectionString, containerName);
await container.CreateIfNotExistsAsync();
BlobClient blobClient = container.GetBlobClient(blobName);

builder.Services.AddDataProtection().PersistKeysToAzureBlobStorage(blobClient);

Startup.ConfigureServices 中:

string connectionString = "{CONNECTION STRING}";
string containerName = "{CONTAINER NAME}";
string blobName = "keys.xml";
var container = new BlobContainerClient(connectionString, containerName);
await container.CreateIfNotExistsAsync();
BlobClient blobClient = container.GetBlobClient(blobName);

services.AddDataProtection().PersistKeysToAzureBlobStorage(blobClient);

Redis

Microsoft.AspNetCore.DataProtection.StackExchangeRedis 套件可讓您將資料保護金鑰儲存在 Redis 快取中。 金鑰可以在 Web 應用程式的數個執行個體之間共用。 應用程式可以跨多部伺服器共用驗證 cookies 或 CSRF 保護。

Microsoft.AspNetCore.DataProtection.Redis 套件可讓您將資料保護金鑰儲存在 Redis 快取中。 金鑰可以在 Web 應用程式的數個執行個體之間共用。 應用程式可以跨多部伺服器共用驗證 cookies 或 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");
}

警告

使用 Redis 保存資料保護金鑰時,請注意 Redis 在重新啟動時預設不會保存資料。 這可能會導致資料保護發出新金鑰,使先前受保護的資料失效。

您可以設定 Redis 以啟用資料持久性,以減輕此問題:Redis 文件包含 如何設定持久性的資訊。 如果您使用 Azure 受控 Redis,請確定您已啟用資料持續性。 適用於 Redis 的 Azure 快取 需要進階或更高層級才能啟用資料持續性。

如需詳細資訊,請參閱下列主題:

註冊表

僅適用於 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 來指定自己的金鑰持續性機制。