ASP.NET Core でのキー ストレージ プロバイダー

データ保護システムでは、暗号化キーを永続化する必要がある場所を決定するために、既定で検出メカニズムが使用されます。 開発者は、既定の検出メカニズムをオーバーライドし、手動で場所を指定できます。

警告

明示的なキー永続化の場所を指定した場合、データ保護システムでは保存時の既定のキー暗号化メカニズムが登録解除されるので、キーは保存時に暗号化されなくなります。 運用展開のためには、追加で明示的なキー暗号化メカニズムを指定することをお勧めします。

ファイル システム

ファイル システム ベースのキー リポジトリを構成するには、次に示すように PersistKeysToFileSystem 構成ルーチンを呼び出します。 キーを格納する必要があるリポジトリを指し示す DirectoryInfo を指定します。

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

DirectoryInfo を使用すると、ローカル マシンのディレクトリを指し示すことも、ネットワーク共有上のフォルダーを指し示すこともできます。 ローカル マシン上のディレクトリを指し示す場合 (ローカル マシン上のアプリだけがこのリポジトリを使用するためのアクセスを必要とするというシナリオ) は (Windows 上で) Windows DPAPI を使用して、保存時のキーを暗号化することを検討してください。 それ以外の場合は、X.509 証明書を使用して保存時のキーを暗号化することを検討してください。

Azure Storage

Azure.Extensions.AspNetCore.DataProtection.Blobs パッケージを使用すると、Azure Blob Storage にデータ保護キーを格納できます。 キーは、Web アプリの複数のインスタンス間で共有できます。 アプリは、複数のサーバー間で認証の cookie や CSRF 保護を共有できます。

Azure Blob Storage プロバイダーを構成するには、いずれかの 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);

Note

ストレージ アカウントへの接続文字列は、Azure Portal の [アクセス キー] セクションで、または次の 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");
}

詳細については、次のトピックを参照してください。

Registry

Windows の展開にのみ適用されます。

アプリに、ファイル システムへの書き込みアクセスがない場合があります。 アプリが仮想サービス アカウントとして実行されているシナリオを考えてください (w3wp.exe のアプリ プール ID など)。 このような場合、管理者は、サービス アカウント ID によってアクセスできるレジストリ キーをプロビジョニングできます。 次に示すように、PersistKeysToRegistry 拡張メソッドを呼び出します。 暗号化キーを格納する必要がある場所を指し示す RegistryKey を指定します。

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

重要

Windows DPAPI を使用して保存時にキーを暗号化することをお勧めします。

Entity Framework Core

The 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 を使用している場合は、MyKeysContext の代わりに、お使いの DbContext の名前を使用します。

DataProtectionKeys クラス/エンティティには、次の表に示す構造が採用されています。

プロパティ/フィールド CLR 型 SQL 型
Id int int、PK、IDENTITY(1,1)、NULL 以外
FriendlyName string nvarchar(MAX)、NULL
Xml string nvarchar(MAX)、NULL

カスタム キー リポジトリ

付属のメカニズムが適切でない場合には、カスタムの IXmlRepository を提供することで、開発者が独自のキー永続化メカニズムを指定できます。