データ保護システムを初期化すると、運用環境に基づく既定の設定が適用されます。 これらの設定は、1 台のコンピューター上で実行するアプリに適しています。 ただし、場合によっては、開発者が既定の設定を変更する必要があります。
- アプリが複数のコンピューターに分散されている。
- コンプライアンス上の理由から。
これらのシナリオに向けて、データ保護システムには豊富な構成 API が用意されています。
警告
構成ファイルと同様に、適切なアクセス許可を使ってデータ保護のキー リングを保護する必要があります。 保存時のキーを暗号化することもできますが、これによってサイバー攻撃者が新しいキーを作成できなくなるわけではありません。 その結果、アプリのセキュリティが影響を受けます。 構成ファイルを保護する方法と同様に、データ保護で構成される保存場所へのアクセスは、そのアプリ自体に制限する必要があります。 たとえば、キー リングをディスクに格納する場合は、ファイル システムのアクセス許可を使います。 Web アプリが実行されている ID にのみ、そのディレクトリへの読み取り、書き込み、作成アクセス権があることを確認します。 Azure Blob Storage を使う場合は、その Web アプリだけが BLOB ストアでの読み取り、書き込み、または新しいエントリの作成を行えるようにする必要があります。
拡張メソッド AddDataProtection から IDataProtectionBuilder が返されます。 IDataProtectionBuilder
によって、データ保護オプションを構成するために連結できる各拡張メソッドが公開されます。
注
この記事は、Docker コンテナー内で実行されるアプリ用に作成されました。 Docker コンテナーでは、アプリは常に同じパスを持つため、アプリケーション識別子も同じです。 複数の環境 (ローカル環境やデプロイ環境など) で実行する必要があるアプリは、その環境の既定のアプリケーション識別子を設定する必要があります。 複数の環境でアプリを実行する方法については、この記事では説明しません。
この記事で使うデータ保護拡張機能には、次の NuGet パッケージが必要です。
Azure Key Vault でキーを保護する (ProtectKeysWithAzureKeyVault
)
開発者の資格情報を使用して Azure Key Vault をローカルで操作するには、Visual Studio でストレージ アカウントにサインインするか、 Azure CLI でサインインします。 Azure CLI をまだインストールしていない場合は、「Azure CLI をインストールする方法」を参照してください。 Visual Studio を使用していない場合は、Visual Studio の [開発者用 PowerShell] パネルまたはコマンド シェルから、次のコマンドを実行できます。
az login
詳細については、「 開発者ツールを使用した Azure へのサインイン」を参照してください。
Entra または Azure portal でキー ボールトを設定する際:
Azure ロールベースのアクセス制御 (RBAC) を使用するようにキー・ボールトを構成します。 ローカルでの開発やテストを含め、 Azure Virtual Network で動作していない場合は、 ネットワーク ステップでのパブリック アクセスが 有効 になっていることを確認します (オン)。 パブリック アクセスを有効にすると、キー ボールト エンドポイントのみが露出されます。 認証されたアカウントは引き続きアクセスに必要です。
Key Vault Crypto User ロールを使用して、Azure マネージド Identityを作成します (または、使用する予定の既存のマネージド Identityにロールを追加します)。 デプロイをホストしている Azure App Service にマネージド Identity を割り当てます: Settings>Identity>User assigned>Add。
注
Azure CLI または Visual Studio の Azure サービス認証を使用して、BLOB アクセスの承認されたユーザーを使用してアプリをローカルで実行する予定の場合は、Key Vault Crypto User ロールを使用して、Access Control (IAM) に開発者の Azure ユーザー アカウントを追加します。 Visual Studio で Azure CLI を使用する場合は、Developer PowerShell パネルから
az login
コマンドを実行し、プロンプトに従ってテナントで認証します。キー暗号化がアクティブな場合、キー ファイル内のキーにコメント "This key is encrypted with Azure Key Vault." が含まれる場合は、アプリを起動した後、キー行の末尾にあるコンテキスト メニューから [表示/編集] コマンドを選択して、キー コンテナーのセキュリティが適用されていることを確認します。
必要に応じて、期限切れまたはローテーションされたキー コンテナー キーに基づいてデータ保護キーを使用してペイロードの暗号化を解除することを気にすることなく、キー コンテナーのキーの自動ローテーションを有効にすることができます。 生成された各データ保護キーには、暗号化に使用されるキー コンテナー キーへの参照が含まれます。 期限切れのキー コンテナー キーを保持していることを確認し、キー コンテナー内で削除しないでください。 さらに、アプリのキー ボールト構成では、識別子の末尾にキー GUID を置かない、バージョンのないキー識別子を使用します(例:
https://contoso.vault.azure.net/keys/data-protection
)。 データ保護キーのローテーション時に新しいキー コンテナー キーが使用されるようにするには、キー コンテナー キーがデータ保護キーよりも頻繁にローテーションされる両方のキーに対して同様のローテーション期間を使用します。
Azure Key Vault を使用してキーを保護すると、キー リングの保存場所を含む自動データ保護設定を無効にする IXmlEncryptor が実装されます。 Blob Storage にキーを格納するように Azure Blob Storage プロバイダーを構成するには、 ASP.NET Core のキー ストレージ プロバイダーの ガイダンスに従って、アプリで PersistKeysToAzureBlobStorage オーバーロードのいずれかを呼び出します。 次の例では、Azure のマネージド Identityを使用してロールベースのアクセス制御 (RBAC) を行い、BLOB URI とトークン資格情報 (TokenCredential) を受け入れるオーバーロードを使用します。
Azure Key Vault プロバイダーを構成するには、 ProtectKeysWithAzureKeyVault オーバーロードのいずれかを呼び出します。 次の例では、キー識別子とトークン資格情報 (TokenCredential) を受け入れるオーバーロードを使用しています。運用環境では RBAC 用のマネージド Identity (ManagedIdentityCredential) を使用し、開発およびテスト環境では DefaultAzureCredential を使用します。 他のオーバーロードは、キー ボルト クライアントまたはクライアント シークレットを持つアプリ クライアント ID のいずれかを受け入れます。 詳細については、「ASP.NET Core でのキー ストレージ プロバイダー」を参照してください。
Azure SDK の API と認証の詳細については、「Azure Identity ライブラリを使用して Azure サービスに対する .NET アプリを認証する」および「Azure ロールベースのアクセス制御を使用して Key Vault キー、証明書、シークレットへのアクセスを提供する」を参照してください。 ログ記録のガイダンスについては、「 Azure SDK for .NET を使用したログ記録: クライアント登録なしのログ記録」を参照してください。 依存性注入を使用しているアプリは、AddAzureClientsCoreを呼び出し、enableLogForwarding
に対してtrue
を渡すことで、ロギングインフラストラクチャを作成して接続できます。
サービスが登録されている 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)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}
: Azure マネージド Identity クライアント ID (GUID)。
{TENANT ID}
: テナント ID。
{APPLICATION NAME}
: SetApplicationName データ保護システム内でこのアプリの一意の名前を設定します。 この値は、アプリのデプロイ間で一致する必要があります。
{BLOB URI}
: キー ファイルへの完全な URI。 URI は、キー ファイルの作成時に Azure Storage によって生成されます。 SAS は使用しないでください。
{KEY IDENTIFIER}
: キー暗号化に使用される Azure Key Vault キー識別子。 アクセス ポリシーを使用すると、アプリケーションは、 Get
、 Unwrap Key
、および Wrap Key
のアクセス許可を持つキー コンテナーにアクセスできます。 キーのバージョンは、作成後に Entra または Azure portal のキーから取得されます。 キー コンテナー キーの自動ローテーションを有効にする場合は、アプリのキー コンテナー構成でバージョンレスのキー識別子を使用してください。ここで、識別子の末尾にキー GUID が配置されません (例: https://contoso.vault.azure.net/keys/data-protection
)。
アプリが Azure Key Vault と通信して承認するには、 Azure.Identity
NuGet パッケージ がアプリによって参照されている必要があります。
注
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
注
非運用環境では、前の例では、 DefaultAzureCredential を使用して認証を簡略化し、Azure ホスティング環境で使用される資格情報とローカル開発で使用される資格情報を組み合わせて Azure にデプロイするアプリを開発しています。 詳細については、「 システム割り当てマネージド ID を使用して Azure リソースに対して Azure でホストされる .NET アプリを認証する」を参照してください。
アプリで古い Azure パッケージ (Microsoft.AspNetCore.DataProtection.AzureStorage
と Microsoft.AspNetCore.DataProtection.AzureKeyVault
) を使用している場合は、これらの参照を 削除 し、 Azure.Extensions.AspNetCore.DataProtection.Blobs
および Azure.Extensions.AspNetCore.DataProtection.Keys
パッケージにアップグレードすることをお勧めします。 新しいパッケージは、主要なセキュリティと安定性の問題に対処します。
代替の Shared-Access Signature (SAS) アプローチ: Azure Blob Storage のキー BLOB にアクセスするためにマネージド Identity を使用する代わりに、SAS トークンを使用して BLOB URI を受け入れる PersistKeysToAzureBlobStorage オーバーロードを呼び出すことができます。 次の例では、前の例に示すように、TokenCredentialに対して ManagedIdentityCredential (運用) またはDefaultAzureCredential (開発とテスト) を引き続き使用します。
builder.Services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{APPLICATION NAME}
: SetApplicationName データ保護システム内でこのアプリの一意の名前を設定します。 この値は、アプリのデプロイ間で一致する必要があります。
{BLOB URI WITH SAS}
: クエリ文字列パラメーターとして SAS トークンを使用してキー ファイルを格納する必要がある完全な URI。 URI は、アップロードされたキー ファイルの SAS を要求すると、Azure Storage によって生成されます。
{KEY IDENTIFIER}
: キー暗号化に使用される Azure Key Vault キー識別子。 アクセス ポリシーを使用すると、アプリケーションは、 Get
、 Unwrap Key
、および Wrap Key
のアクセス許可を持つキー コンテナーにアクセスできます。 キーのバージョンは、作成後に Entra または Azure portal のキーから取得されます。 キー コンテナー キーの自動ローテーションを有効にする場合は、アプリのキー コンテナー構成でバージョンレスのキー識別子を使用してください。ここで、識別子の末尾にキー GUID が配置されません (例: https://contoso.vault.azure.net/keys/data-protection
)。
ファイル システムにキーを保持する (PersistKeysToFileSystem
)
%LOCALAPPDATA% の既定の場所ではなく UNC 共有にキーを格納するには、PersistKeysToFileSystem を使ってシステムを構成します。
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
警告
キーの永続化の場所を変更すると、DPAPI が適切な暗号化メカニズムであるかどうかが認識されないため、保存中のキーはシステムによって自動的に暗号化されなくなります。
データベースにキーを保持する (PersistKeysToDbContext
)
EntityFramework を使ってデータベースにキーを格納するには、Microsoft.AspNetCore.DataProtection.EntityFrameworkCore パッケージを使ってシステムを構成します。
builder.Services.AddDataProtection()
.PersistKeysToDbContext<SampleDbContext>();
上のコードでは、構成したデータベースにキーが格納されます。 使われているデータベース コンテキストでは、IDataProtectionKeyContext
を実装する必要があります。 IDataProtectionKeyContext
ではプロパティ DataProtectionKeys
が公開されます
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
このプロパティは、キーが格納されるテーブルを表します。 手動で、または DbContext
の移行を使ってテーブルを作成します。 詳細については、DataProtectionKeyを参照してください。
キー構成 API の保護 (ProtectKeysWith\*
)
ProtectKeysWith\*
構成 API のいずれかを呼び出すことによって、保存中のキーを保護するようにシステムを構成できます。 UNC 共有にキーを格納し、保存中のキーを特定の X.509 証明書で暗号化する次の例を考えてみましょう。
ファイルからX509Certificate2をProtectKeysWithCertificateに提供するには、X509CertificateLoader.LoadCertificateFromFileを呼び出します。
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));
次のコード例は、拇印を使用して証明書を読み込む方法を示しています。
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);
ファイルから読み込んだ証明書など、X509Certificate2 を ProtectKeysWithCertificate に指定することができます。
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));
次のコード例は、拇印を使用して証明書を読み込む方法を示しています。
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);
組み込みのキー暗号化メカニズムの例と説明については、「 ASP.NET Core を使用した Windows と Azure での保存時のキー暗号化」を参照してください。
任意の証明書でキーの保護を解除する (UnprotectKeysWithAnyCertificate
)
X509Certificate2 で UnprotectKeysWithAnyCertificate 証明書の配列を使って、証明書のローテーションと保存時のキーの暗号化解除を行うことができます。
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]))
.UnprotectKeysWithAnyCertificate(
new X509Certificate2("certificate_1.pfx", builder.Configuration["CertificatePassword_1"]),
new X509Certificate2("certificate_2.pfx", builder.Configuration["CertificatePassword_2"]));
既定のキーの有効期間を設定する (SetDefaultKeyLifetime
)
キー有効期間が既定の 90 日ではなく 14 日になるようにシステムを構成するには、SetDefaultKeyLifetime を使います。
builder.Services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
アプリケーション名を設定する (SetApplicationName
)
既定では、データ保護システムによって各アプリが、それらのコンテンツ ルート パスに基づいて互いに分離されます。同じ物理キー リポジトリを共有している場合でも同様です。 この分離により、各アプリで互いの保護されたペイロードを把握できなくなります。
保護されたペイロードをアプリ間で共有するには:
- 各アプリで同じ値を使って SetApplicationName を構成します。
- アプリ全体で同じバージョンのデータ保護 API スタックを使います。 各アプリのプロジェクト ファイルで、次のいずれかを実行します。
- Microsoft.AspNetCore.App メタパッケージを使って、同じ共有フレームワーク バージョンを参照します。
- 同じデータ保護パッケージ バージョンを参照します。
builder.Services.AddDataProtection()
.SetApplicationName("<sharedApplicationName>");
SetApplicationName では内部的に DataProtectionOptions.ApplicationDiscriminator が設定されます。 トラブルシューティングの目的で、フレームワークによって識別子に代入される値は、WebApplication で Program.cs
がビルドされる後に配置された次のコードによってログに記録できます。
var discriminator = app.Services.GetRequiredService<IOptions<DataProtectionOptions>>()
.Value.ApplicationDiscriminator;
app.Logger.LogInformation("ApplicationDiscriminator: {ApplicationDiscriminator}", discriminator);
識別子の使用方法について詳しくは、この記事の後半にある以下のセクションを参照してください。
警告
.NET 6 では、WebApplicationBuilder によって、コンテンツのルート パスが DirectorySeparatorChar で終わるように正規化されます。 たとえば、Windows では、コンテンツのルート パスは \
で終わります。Linux では /
です。 他のホストではパスは正規化されません。 HostBuilder または WebHostBuilder から移行するほとんどのアプリでは DirectorySeparatorChar
を終了しないため、同じアプリ名を共有することはありません。 この問題を回避するには、次のコードに示すように、ディレクトリ区切り文字を削除し、アプリ名を手動で設定します。
using System.Reflection;
using Microsoft.AspNetCore.DataProtection;
var builder = WebApplication.CreateBuilder(args);
var trimmedContentRootPath =
builder.Environment.ContentRootPath.TrimEnd(Path.DirectorySeparatorChar);
builder.Services.AddDataProtection().SetApplicationName(trimmedContentRootPath);
var app = builder.Build();
app.MapGet("/", () => Assembly.GetEntryAssembly()!.GetName().Name);
app.Run();
自動キー生成を無効にする (DisableAutomaticKeyGeneration
)
有効期限が近づいたキーをアプリで自動的にロール (新しいキーを作成) したくない場合があります。 このシナリオ例の 1 つは、アプリがプライマリとセカンダリの関係で設定されていて、プライマリ アプリだけがキー管理の問題を担当し、セカンダリ アプリにはキー リングの読み取り専用ビューがあるだけという場合です。 DisableAutomaticKeyGeneration を使ってシステムを構成することで、キー リングを読み取り専用として処理するようにセカンダリ アプリを構成できます。
builder.Services.AddDataProtection()
.DisableAutomaticKeyGeneration();
アプリケーションごとの分離
ASP.NET Core ホストによってデータ保護システムが提供されている場合、各アプリは自動的に互いに分離されます。これは、それらのアプリが同じワーカー プロセス アカウントで実行され、同じマスター キー マテリアルが使われている場合でも同様です。 これは、System.Web の <machineKey>
要素の IsolateApps 修飾子に似ています。
この分離メカニズムは、ローカル コンピューター上の各アプリを一意のテナントと見なすことで機能するため、特定のアプリに対してルートが指定された IDataProtector には、そのアプリ ID が識別子 (ApplicationDiscriminator) として自動的に含まれます。 アプリの一意の ID は、そのアプリの物理パスです。
- IIS でホストされているアプリの場合、一意の ID はアプリの IIS 物理パスです。 アプリが Web ファーム環境に展開されている場合、IIS 環境がその Web ファーム内のすべてのコンピューターにわたって同じように構成されていると仮定すれば、この値は変化しません。
- Kestrel サーバー上で実行しているセルフホステッド アプリの場合、一意の ID はディスク上のアプリへの物理パスです。
一意識別子は、個々のアプリとそのコンピューター自体のどちらをリセットした後でも維持されるように設計されています。
この分離メカニズムは、アプリが悪意のあるものではないことを想定しています。 悪意のあるアプリは、同じワーカー プロセス アカウントで実行されている他のすべてのアプリに常に影響を与える可能性があります。 アプリが相互に信頼されていない共有ホスティング環境の場合、ホスティング プロバイダーによってアプリ間の OS レベルの分離を確保するための手順が実行される必要があります。これにはアプリの基になるキー リポジトリの分離も含まれます。
データ保護システムが ASP.NET Core ホストによって提供されていない場合 (DataProtectionProvider
具象型を使ってそれをインスタンス化する場合など)、アプリの分離は既定で無効になっています。 アプリの分離が無効になっている場合、同じキー マテリアルでサポートされているすべてのアプリで、適切な目的を提供している限り、ペイロードを共有できます。 この環境でアプリの分離を実現するには、構成オブジェクトで SetApplicationName
メソッドを呼び出し、アプリごとに一意の名前を指定します。
データ保護とアプリの分離
アプリの分離については、次の点を考慮してください。
複数のアプリが同じキー リポジトリを指している場合は、それらのアプリで同じマスター キー マテリアルを共有することが目的です。 データ保護は、キー リングを共有しているすべてのアプリがそのキー リング内のすべての項目にアクセスできるという前提で開発されています。 アプリケーション固有の鍵を、キーリングにより提供された鍵から派生した識別子を使用して分離します。 項目レベルのアクセス許可(Azure KeyVault が提供するもので、追加の分離を強化するために使用されるものなど)は、特に必要とはされていません。 項目レベルのアクセス許可を試行すると、アプリケーション エラーが生成されます。 組み込みのアプリケーション分離に依存したくない場合は、別々のキー ストアの場所を使う必要があり、アプリケーション間で共有すべきではありません。
アプリケーション識別子 (ApplicationDiscriminator) は、異なるアプリで同じマスター キー マテリアルを共有しながら、それらの暗号化ペイロードを互いに区別できるようにするために使われます。 各アプリで互いの暗号化ペイロードを読み取れるようにするには、それらのアプリケーション識別子が同じである必要があります。それは
SetApplicationName
を呼び出すことで設定できます。アプリが侵害された場合 (RCE 攻撃など)、そのアプリからアクセスできるすべてのマスター キー マテリアルも、保存時の保護の状態に関係なく、侵害されたと見なす必要があります。 これは、2 つのアプリが同じリポジトリを指している場合、それらで異なるアプリ識別子が使われていても、片方の侵害が機能的には両方の侵害に相当することを意味します。
この両方の侵害と機能的に同等であるという条項は、2つのアプリが休止状態でのキー保護に異なるメカニズムを使用している場合でも適用されます。 通常、これは想定される構成ではありません。 保存時の保護メカニズムは、サイバー攻撃者がリポジトリへの読み取りアクセス権を取得した場合に保護を提供することを目的としています。 (おそらくアプリ内でコード実行権限を取得したため) リポジトリへの書き込みアクセス権を取得した攻撃者は、悪意のあるキーをストレージに挿入できます。 データ保護システムでは、キー リポジトリへの書き込みアクセス権を取得した攻撃者に対する保護は意図的に提供されていません。
各アプリを互いに完全に分離した状態に維持する必要がある場合は、異なるキー リポジトリを使う必要があります。 これは当然、"分離" の定義から外れています。 すべてのアプリが互いのデータ ストアに対する読み取りアクセス権と書き込みアクセス権を持っている場合、アプリは分離されて "いません"。
を使用してアルゴリズムを変更する UseCryptographicAlgorithms
データ保護スタックを使うと、新しく生成されたキーによって使われる既定のアルゴリズムを変更することができます。 これを行う最も簡単な方法は、構成コールバックから UseCryptographicAlgorithms を呼び出すことです。
builder.Services.AddDataProtection()
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
既定の EncryptionAlgorithm は AES-256-CBC で、既定の ValidationAlgorithm は HMACSHA256 です。 既定のポリシーは、システム管理者がコンピューター全体のポリシーを使って設定できますが、UseCryptographicAlgorithms
を明示的に呼び出すと既定のポリシーはオーバーライドされます。
UseCryptographicAlgorithms
の呼び出しを使うと、定義済みの組み込みリストから目的のアルゴリズムを指定できます。 アルゴリズムの実装について心配する必要はありません。 上記のシナリオの場合、データ保護システムでは、Windows 上で実行されている場合、AES の CNG 実装の使用が試みられます。 それ以外の場合は、マネージド System.Security.Cryptography.Aes クラスにフォールバックします。
UseCustomCryptographicAlgorithms を呼び出すことで、手動で実装を指定できます。
ヒント
アルゴリズムを変更しても、キー リング内の既存のキーには影響しません。 新たに生成されたキーにのみ影響します。
カスタム マネージド アルゴリズムの指定
カスタム マネージド アルゴリズムを指定するには、実装の種類を示す ManagedAuthenticatedEncryptorConfiguration インスタンスを作成します。
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new ManagedAuthenticatedEncryptorConfiguration
{
// A type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// A type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
一般に、*Type プロパティでは、SymmetricAlgorithm と KeyedHashAlgorithm の具体的で、インスタンス化可能 (パブリックのパラメーターなしの ctor を使用) な実装を指す必要がありますが、システムでは、便宜上、typeof(Aes)
などのいくつかの値が特別なケースとして扱われます。
注
SymmetricAlgorithm のキーの長さは 128 ビット以上、ブロック サイズは 64 ビット以上である必要があります。また、PKCS #7 パディングによる CBC モードの暗号化がサポートされている必要があります。 KeyedHashAlgorithm は、ダイジェスト サイズが >=128 ビットである必要があり、ハッシュ アルゴリズムのダイジェストの長さと同じ長さのキーをサポートする必要があります。 KeyedHashAlgorithm は、必ずしも HMAC である必要はありません。
カスタム Windows CNG アルゴリズムの指定
CBC モードの暗号化と HMAC 検証を使ってカスタムの Windows CNG アルゴリズムを指定するには、アルゴリズム情報を含む CngCbcAuthenticatedEncryptorConfiguration インスタンスを作成します。
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngCbcAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// Passed to BCryptOpenAlgorithmProvider
HashAlgorithm = "SHA256",
HashAlgorithmProvider = null
});
注
対称ブロック暗号アルゴリズムのキーの長さは >= 128 ビット、ブロック サイズは >= 64 ビットである必要があります。また、PKCS #7 パディングによる CBC モードの暗号化をサポートする必要があります。 ハッシュ アルゴリズムのダイジェスト サイズは >= 128 ビットである必要があり、BCRYPT_ALG_HANDLE_HMAC_FLAG フラグを使って開かれることをサポートする必要があります。 *Provider プロパティを null に設定すると、指定したアルゴリズムの既定のプロバイダーを使用できます。 詳細については、BCryptOpenAlgorithmProvider に関するドキュメントを参照してください。
Galois/Counter モードの暗号化と検証を使ってカスタムの Windows CNG アルゴリズムを指定するには、アルゴリズム情報を含む CngGcmAuthenticatedEncryptorConfiguration インスタンスを作成します。
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngGcmAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
注
対称ブロック暗号アルゴリズムのキーの長さは >=128 ビット、ブロック サイズはちょうど 128 ビットである必要があります。また、GCM 暗号化をサポートする必要があります。 EncryptionAlgorithmProvider プロパティを null に設定すると、指定したアルゴリズムの既定のプロバイダーを使用できます。 詳細については、BCryptOpenAlgorithmProvider に関するドキュメントを参照してください。
その他のカスタム アルゴリズムの指定
ファーストクラスの API としては公開されていませんが、データ保護システムにはほとんど全種類のアルゴリズムを指定できるようにする拡張性があります。 たとえば、すべてのキーをハードウェア セキュリティ モジュール (HSM) 内で保持し、コアの暗号化および暗号化解除ルーチンのカスタム実装を提供することができます。 詳細については、IAuthenticatedEncryptorに関するページの を参照してください。
Docker コンテナーでホストするときのキーの永続化
Docker コンテナーでホストする場合は、次のいずれかの方法でキーを管理する必要があります。
- 共有ボリュームやホストによってマウントされたボリュームなど、コンテナーの有効期間を超えて永続化される Docker ボリュームのフォルダー。
- Azure Blob Storage (「
ProtectKeysWithAzureKeyVault
」セクションを参照) や Redis などの外部プロバイダー。
Redis でのキーの永続化
キーの格納には、Redis データ永続化がサポートされている Redis バージョンのみを使う必要があります。 Azure Blob Storage は永続的であり、キーの格納に使用できます。 詳細については、こちらの GitHub の問題のページを参照してください。
ログの記録
問題を診断するには、 Information
以下のレベルのログ記録を有効にします。 次の appsettings.json
ファイルを使用すると、Data Protection API の情報ログが有効になります。
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.DataProtection": "Information"
}
},
"AllowedHosts": "*"
}
ログ記録に関する詳細については、「.NET Core と ASP.NET Core でのログ記録」を参照してください。
その他のリソース
データ保護システムを初期化すると、運用環境に基づく既定の設定が適用されます。 これらの設定は、1 台のコンピューター上で実行するアプリに適しています。 ただし、場合によっては、開発者が既定の設定を変更する必要があります。
- アプリが複数のコンピューターに分散されている。
- コンプライアンス上の理由から。
これらのシナリオに向けて、データ保護システムには豊富な構成 API が用意されています。
警告
構成ファイルと同様に、適切なアクセス許可を使ってデータ保護のキー リングを保護する必要があります。 保存時のキーを暗号化することもできますが、これによってサイバー攻撃者が新しいキーを作成できなくなるわけではありません。 その結果、アプリのセキュリティが影響を受けます。 構成ファイルを保護する方法と同様に、データ保護で構成される保存場所へのアクセスは、そのアプリ自体に制限する必要があります。 たとえば、キー リングをディスクに格納する場合は、ファイル システムのアクセス許可を使います。 Web アプリが実行されている ID にのみ、そのディレクトリへの読み取り、書き込み、作成アクセス権があることを確認します。 Azure Blob Storage を使用する場合、BLOB ストアで新しいエントリを読み取り、書き込み、または作成できるのは Web アプリだけです。
拡張メソッド AddDataProtection は IDataProtectionBuilderを返します。このメソッドは、データ保護オプションを構成するために連結できる拡張メソッドを公開します。
この記事で使うデータ保護拡張機能には、次の NuGet パッケージが必要です。
注
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
Azure Key Vault でキーを保護する (ProtectKeysWithAzureKeyVault
)
開発者の資格情報を使用して Azure Key Vault をローカルで操作するには、Visual Studio でストレージ アカウントにサインインするか、 Azure CLI でサインインします。 Azure CLI をまだインストールしていない場合は、「Azure CLI をインストールする方法」を参照してください。 Visual Studio を使用していない場合は、Visual Studio の [開発者用 PowerShell] パネルまたはコマンド シェルから、次のコマンドを実行できます。
az login
詳細については、「 開発者ツールを使用した Azure へのサインイン」を参照してください。
Entra または Azure portal でキー ボールトを設定する際:
Azure ロールベースのアクセス制御 (RBAC) を使用するようにキー・ボールトを構成します。 ローカルでの開発やテストを含め、 Azure Virtual Network で動作していない場合は、 ネットワーク ステップでのパブリック アクセスが 有効 になっていることを確認します (オン)。 パブリック アクセスを有効にすると、キー ボールト エンドポイントのみが露出されます。 認証されたアカウントは引き続きアクセスに必要です。
Key Vault Crypto User ロールを使用して、Azure マネージド Identityを作成します (または、使用する予定の既存のマネージド Identityにロールを追加します)。 デプロイをホストしている Azure App Service にマネージド Identity を割り当てます: Settings>Identity>User assigned>Add。
注
Azure CLI または Visual Studio の Azure サービス認証を使用して、BLOB アクセスの承認されたユーザーを使用してアプリをローカルで実行する予定の場合は、Key Vault Crypto User ロールを使用して、Access Control (IAM) に開発者の Azure ユーザー アカウントを追加します。 Visual Studio で Azure CLI を使用する場合は、Developer PowerShell パネルから
az login
コマンドを実行し、プロンプトに従ってテナントで認証します。キー暗号化がアクティブな場合、キー ファイル内のキーにコメント "This key is encrypted with Azure Key Vault." が含まれる場合は、アプリを起動した後、キー行の末尾にあるコンテキスト メニューから [表示/編集] コマンドを選択して、キー コンテナーのセキュリティが適用されていることを確認します。
必要に応じて、期限切れまたはローテーションされたキー コンテナー キーに基づいてデータ保護キーを使用してペイロードの暗号化を解除することを気にすることなく、キー コンテナーのキーの自動ローテーションを有効にすることができます。 生成された各データ保護キーには、暗号化に使用されるキー コンテナー キーへの参照が含まれます。 期限切れのキー コンテナー キーを保持していることを確認し、キー コンテナー内で削除しないでください。 さらに、アプリのキー ボールト構成では、識別子の末尾にキー GUID を置かない、バージョンのないキー識別子を使用します(例:
https://contoso.vault.azure.net/keys/data-protection
)。 データ保護キーのローテーション時に新しいキー コンテナー キーが使用されるようにするには、キー コンテナー キーがデータ保護キーよりも頻繁にローテーションされる両方のキーに対して同様のローテーション期間を使用します。
Azure Key Vault を使用してキーを保護すると、キー リングの保存場所を含む自動データ保護設定を無効にする IXmlEncryptor が実装されます。 Blob Storage にキーを格納するように Azure Blob Storage プロバイダーを構成するには、 ASP.NET Core のキー ストレージ プロバイダーの ガイダンスに従って、アプリで PersistKeysToAzureBlobStorage オーバーロードのいずれかを呼び出します。 次の例では、Azure のマネージド Identityを使用してロールベースのアクセス制御 (RBAC) を行い、BLOB URI とトークン資格情報 (TokenCredential) を受け入れるオーバーロードを使用します。
Azure Key Vault プロバイダーを構成するには、 ProtectKeysWithAzureKeyVault オーバーロードのいずれかを呼び出します。 次の例では、キー識別子とトークン資格情報 (TokenCredential) を受け入れるオーバーロードを使用しています。運用環境では RBAC 用のマネージド Identity (ManagedIdentityCredential) を使用し、開発およびテスト環境では DefaultAzureCredential を使用します。 他のオーバーロードは、キー ボルト クライアントまたはクライアント シークレットを持つアプリ クライアント ID のいずれかを受け入れます。 詳細については、「ASP.NET Core でのキー ストレージ プロバイダー」を参照してください。
Azure SDK の API と認証の詳細については、「Azure Identity ライブラリを使用して Azure サービスに対する .NET アプリを認証する」および「Azure ロールベースのアクセス制御を使用して Key Vault キー、証明書、シークレットへのアクセスを提供する」を参照してください。 ログ記録のガイダンスについては、「 Azure SDK for .NET を使用したログ記録: クライアント登録なしのログ記録」を参照してください。 依存性注入を使用しているアプリは、AddAzureClientsCoreを呼び出し、enableLogForwarding
に対してtrue
を渡すことで、ロギングインフラストラクチャを作成して接続できます。
サービスが登録されている 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);
}
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}
: Azure マネージド Identity クライアント ID (GUID)。
{TENANT ID}
: テナント ID。
{APPLICATION NAME}
: SetApplicationName データ保護システム内でこのアプリの一意の名前を設定します。 この値は、アプリのデプロイ間で一致する必要があります。
{BLOB URI}
: キー ファイルへの完全な URI。 URI は、キー ファイルの作成時に Azure Storage によって生成されます。 SAS は使用しないでください。
{KEY IDENTIFIER}
: キー暗号化に使用される Azure Key Vault キー識別子。 アクセス ポリシーを使用すると、アプリケーションは、 Get
、 Unwrap Key
、および Wrap Key
のアクセス許可を持つキー コンテナーにアクセスできます。 キーのバージョンは、作成後に Entra または Azure portal のキーから取得されます。 キー コンテナー キーの自動ローテーションを有効にする場合は、アプリのキー コンテナー構成でバージョンレスのキー識別子を使用してください。ここで、識別子の末尾にキー GUID が配置されません (例: https://contoso.vault.azure.net/keys/data-protection
)。
アプリが Azure Key Vault と通信して承認するには、 Azure.Identity
NuGet パッケージ がアプリによって参照されている必要があります。
注
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
注
非運用環境では、前の例では、 DefaultAzureCredential を使用して認証を簡略化し、Azure ホスティング環境で使用される資格情報とローカル開発で使用される資格情報を組み合わせて Azure にデプロイするアプリを開発しています。 詳細については、「 システム割り当てマネージド ID を使用して Azure リソースに対して Azure でホストされる .NET アプリを認証する」を参照してください。
アプリで古い Azure パッケージ (Microsoft.AspNetCore.DataProtection.AzureStorage
と Microsoft.AspNetCore.DataProtection.AzureKeyVault
) を使用している場合は、これらの参照を 削除 し、 Azure.Extensions.AspNetCore.DataProtection.Blobs
および Azure.Extensions.AspNetCore.DataProtection.Keys
パッケージにアップグレードすることをお勧めします。 新しいパッケージは、主要なセキュリティと安定性の問題に対処します。
代替の Shared-Access Signature (SAS) アプローチ: Azure Blob Storage のキー BLOB にアクセスするためにマネージド Identity を使用する代わりに、SAS トークンを使用して BLOB URI を受け入れる PersistKeysToAzureBlobStorage オーバーロードを呼び出すことができます。 次の例では、前の例に示すように、TokenCredentialに対して ManagedIdentityCredential (運用) またはDefaultAzureCredential (開発とテスト) を引き続き使用します。
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{APPLICATION NAME}
: SetApplicationName データ保護システム内でこのアプリの一意の名前を設定します。 この値は、アプリのデプロイ間で一致する必要があります。
{BLOB URI WITH SAS}
: クエリ文字列パラメーターとして SAS トークンを使用してキー ファイルを格納する必要がある完全な URI。 URI は、アップロードされたキー ファイルの SAS を要求すると、Azure Storage によって生成されます。
{KEY IDENTIFIER}
: キー暗号化に使用される Azure Key Vault キー識別子。 アクセス ポリシーを使用すると、アプリケーションは、 Get
、 Unwrap Key
、および Wrap Key
のアクセス許可を持つキー コンテナーにアクセスできます。 キーのバージョンは、作成後に Entra または Azure portal のキーから取得されます。 キー コンテナー キーの自動ローテーションを有効にする場合は、アプリのキー コンテナー構成でバージョンレスのキー識別子を使用してください。ここで、識別子の末尾にキー GUID が配置されません (例: https://contoso.vault.azure.net/keys/data-protection
)。
ファイル システムにキーを保持する (PersistKeysToFileSystem
)
%LOCALAPPDATA% の既定の場所ではなく UNC 共有にキーを格納するには、PersistKeysToFileSystem を使ってシステムを構成します。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
}
警告
キーの永続化の場所を変更すると、DPAPI が適切な暗号化メカニズムであるかどうかが認識されないため、保存中のキーはシステムによって自動的に暗号化されなくなります。
データベースにキーを保持する (PersistKeysToDbContext
)
EntityFramework を使ってデータベースにキーを格納するには、Microsoft.AspNetCore.DataProtection.EntityFrameworkCore パッケージを使ってシステムを構成します。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToDbContext<DbContext>()
}
上のコードでは、構成したデータベースにキーが格納されます。 使われているデータベース コンテキストでは、IDataProtectionKeyContext
を実装する必要があります。 IDataProtectionKeyContext
ではプロパティ DataProtectionKeys
が公開されます
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
このプロパティは、キーが格納されるテーブルを表します。 手動で、または DbContext
の移行を使ってテーブルを作成します。 詳細については、DataProtectionKeyを参照してください。
キー構成 API の保護 (ProtectKeysWith\*
)
ProtectKeysWith\*
構成 API のいずれかを呼び出すことによって、保存中のキーを保護するようにシステムを構成できます。 UNC 共有にキーを格納し、保存中のキーを特定の X.509 証明書で暗号化する次の例を考えてみましょう。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(Configuration["Thumbprint"]);
}
ファイルから読み込んだ証明書など、X509Certificate2 を ProtectKeysWithCertificate に指定することができます。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", Configuration["Thumbprint"]));
}
組み込みのキー暗号化メカニズムの例と説明については、「 ASP.NET Core を使用した Windows と Azure での保存時のキー暗号化」を参照してください。
任意の証明書でキーの保護を解除する (UnprotectKeysWithAnyCertificate
)
X509Certificate2 で UnprotectKeysWithAnyCertificate 証明書の配列を使って、証明書のローテーションと保存時のキーの暗号化解除を行うことができます。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", Configuration["MyPasswordKey"));
.UnprotectKeysWithAnyCertificate(
new X509Certificate2("certificate_old_1.pfx", Configuration["MyPasswordKey_1"]),
new X509Certificate2("certificate_old_2.pfx", Configuration["MyPasswordKey_2"]));
}
既定のキーの有効期間を設定する (SetDefaultKeyLifetime
)
キー有効期間が既定の 90 日ではなく 14 日になるようにシステムを構成するには、SetDefaultKeyLifetime を使います。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
}
アプリケーション名を設定する (SetApplicationName
)
既定では、データ保護システムによって各アプリが、それらのコンテンツ ルート パスに基づいて互いに分離されます。同じ物理キー リポジトリを共有している場合でも同様です。 この分離により、各アプリで互いの保護されたペイロードを把握できなくなります。
保護されたペイロードをアプリ間で共有するには:
- 各アプリで同じ値を使って SetApplicationName を構成します。
- アプリ全体で同じバージョンのデータ保護 API スタックを使います。 各アプリのプロジェクト ファイルで、次のいずれかを実行します。
- Microsoft.AspNetCore.App メタパッケージを使って、同じ共有フレームワーク バージョンを参照します。
- 同じデータ保護パッケージ バージョンを参照します。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}");
}
SetApplicationName では内部的に DataProtectionOptions.ApplicationDiscriminator が設定されます。 識別子の使用方法について詳しくは、この記事の後半にある以下のセクションを参照してください。
自動キー生成を無効にする (DisableAutomaticKeyGeneration
)
有効期限が近づいたキーをアプリで自動的にロール (新しいキーを作成) したくない場合があります。 このシナリオ例の 1 つは、アプリがプライマリとセカンダリの関係で設定されていて、プライマリ アプリだけがキー管理の問題を担当し、セカンダリ アプリにはキー リングの読み取り専用ビューがあるだけという場合です。 DisableAutomaticKeyGeneration を使ってシステムを構成することで、キー リングを読み取り専用として処理するようにセカンダリ アプリを構成できます。
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.DisableAutomaticKeyGeneration();
}
アプリケーションごとの分離
ASP.NET Core ホストによってデータ保護システムが提供されている場合、各アプリは自動的に互いに分離されます。これは、それらのアプリが同じワーカー プロセス アカウントで実行され、同じマスター キー マテリアルが使われている場合でも同様です。 これは、System.Web の <machineKey>
要素の IsolateApps 修飾子に似ています。
この分離メカニズムは、ローカル コンピューター上の各アプリを一意のテナントと見なすことで機能するため、特定のアプリに対してルートが指定された IDataProtector には、そのアプリ ID が識別子 (ApplicationDiscriminator) として自動的に含まれます。 アプリの一意の ID は、そのアプリの物理パスです。
- IIS でホストされているアプリの場合、一意の ID はアプリの IIS 物理パスです。 アプリが Web ファーム環境に展開されている場合、IIS 環境がその Web ファーム内のすべてのコンピューターにわたって同じように構成されていると仮定すれば、この値は変化しません。
- Kestrel サーバー上で実行しているセルフホステッド アプリの場合、一意の ID はディスク上のアプリへの物理パスです。
一意識別子は、個々のアプリとそのコンピューター自体のどちらをリセットした後でも維持されるように設計されています。
この分離メカニズムは、アプリが悪意のあるものではないことを想定しています。 悪意のあるアプリは、同じワーカー プロセス アカウントで実行されている他のすべてのアプリに常に影響を与える可能性があります。 アプリが相互に信頼されていない共有ホスティング環境の場合、ホスティング プロバイダーによってアプリ間の OS レベルの分離を確保するための手順が実行される必要があります。これにはアプリの基になるキー リポジトリの分離も含まれます。
データ保護システムが ASP.NET Core ホストによって提供されていない場合 (DataProtectionProvider
具象型を使ってそれをインスタンス化する場合など)、アプリの分離は既定で無効になっています。 アプリの分離が無効になっている場合、同じキー マテリアルでサポートされているすべてのアプリで、適切な目的を提供している限り、ペイロードを共有できます。 この環境でアプリの分離を実現するには、構成オブジェクトで SetApplicationName メソッドを呼び出し、アプリごとに一意の名前を指定します。
データ保護とアプリの分離
アプリの分離については、次の点を考慮してください。
複数のアプリが同じキー リポジトリを指している場合は、それらのアプリで同じマスター キー マテリアルを共有することが目的です。 データ保護は、キー リングを共有しているすべてのアプリがそのキー リング内のすべての項目にアクセスできるという前提で開発されています。 アプリケーション固有の鍵を、キーリングにより提供された鍵から派生した識別子を使用して分離します。 項目レベルのアクセス許可(Azure KeyVault が提供するもので、追加の分離を強化するために使用されるものなど)は、特に必要とはされていません。 項目レベルのアクセス許可を試行すると、アプリケーション エラーが生成されます。 組み込みのアプリケーション分離に依存したくない場合は、別々のキー ストアの場所を使う必要があり、アプリケーション間で共有すべきではありません。
アプリケーション識別子 (ApplicationDiscriminator) は、異なるアプリで同じマスター キー マテリアルを共有しながら、それらの暗号化ペイロードを互いに区別できるようにするために使われます。 各アプリで互いの暗号化ペイロードを読み取れるようにするには、それらのアプリケーション識別子が同じである必要があります。それは
SetApplicationName
を呼び出すことで設定できます。アプリが侵害された場合 (RCE 攻撃など)、そのアプリからアクセスできるすべてのマスター キー マテリアルも、保存時の保護の状態に関係なく、侵害されたと見なす必要があります。 これは、2 つのアプリが同じリポジトリを指している場合、それらで異なるアプリ識別子が使われていても、片方の侵害が機能的には両方の侵害に相当することを意味します。
この両方の侵害と機能的に同等であるという条項は、2つのアプリが休止状態でのキー保護に異なるメカニズムを使用している場合でも適用されます。 通常、これは想定される構成ではありません。 保存時の保護メカニズムは、サイバー攻撃者がリポジトリへの読み取りアクセス権を取得した場合に保護を提供することを目的としています。 (おそらくアプリ内でコード実行権限を取得したため) リポジトリへの書き込みアクセス権を取得した攻撃者は、悪意のあるキーをストレージに挿入できます。 データ保護システムでは、キー リポジトリへの書き込みアクセス権を取得した攻撃者に対する保護は意図的に提供されていません。
各アプリを互いに完全に分離した状態に維持する必要がある場合は、異なるキー リポジトリを使う必要があります。 これは当然、"分離" の定義から外れています。 すべてのアプリが互いのデータ ストアに対する読み取りアクセス権と書き込みアクセス権を持っている場合、アプリは分離されて "いません"。
を使用してアルゴリズムを変更する UseCryptographicAlgorithms
データ保護スタックを使うと、新しく生成されたキーによって使われる既定のアルゴリズムを変更することができます。 これを行う最も簡単な方法は、構成コールバックから UseCryptographicAlgorithms を呼び出すことです。
services.AddDataProtection()
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
既定の EncryptionAlgorithm は AES-256-CBC で、既定の ValidationAlgorithm は HMACSHA256 です。 既定のポリシーは、システム管理者がコンピューター全体のポリシーを使って設定できますが、UseCryptographicAlgorithms
を明示的に呼び出すと既定のポリシーはオーバーライドされます。
UseCryptographicAlgorithms
の呼び出しを使うと、定義済みの組み込みリストから目的のアルゴリズムを指定できます。 アルゴリズムの実装について心配する必要はありません。 上記のシナリオの場合、データ保護システムでは、Windows 上で実行されている場合、AES の CNG 実装の使用が試みられます。 それ以外の場合は、マネージド System.Security.Cryptography.Aes クラスにフォールバックします。
UseCustomCryptographicAlgorithms を呼び出すことで、手動で実装を指定できます。
ヒント
アルゴリズムを変更しても、キー リング内の既存のキーには影響しません。 新たに生成されたキーにのみ影響します。
カスタム マネージド アルゴリズムの指定
カスタム マネージド アルゴリズムを指定するには、実装の種類を示す ManagedAuthenticatedEncryptorConfiguration インスタンスを作成します。
serviceCollection.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new ManagedAuthenticatedEncryptorConfiguration()
{
// A type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// A type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
一般に、*Type プロパティでは、SymmetricAlgorithm と KeyedHashAlgorithm の具体的で、インスタンス化可能 (パブリックのパラメーターなしの ctor を使用) な実装を指す必要がありますが、システムでは、便宜上、typeof(Aes)
などのいくつかの値が特別なケースとして扱われます。
注
SymmetricAlgorithm のキーの長さは 128 ビット以上、ブロック サイズは 64 ビット以上である必要があります。また、PKCS #7 パディングによる CBC モードの暗号化がサポートされている必要があります。 KeyedHashAlgorithm は、ダイジェスト サイズが >=128 ビットである必要があり、ハッシュ アルゴリズムのダイジェストの長さと同じ長さのキーをサポートする必要があります。 KeyedHashAlgorithm は、必ずしも HMAC である必要はありません。
カスタム Windows CNG アルゴリズムの指定
CBC モードの暗号化と HMAC 検証を使ってカスタムの Windows CNG アルゴリズムを指定するには、アルゴリズム情報を含む CngCbcAuthenticatedEncryptorConfiguration インスタンスを作成します。
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngCbcAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// Passed to BCryptOpenAlgorithmProvider
HashAlgorithm = "SHA256",
HashAlgorithmProvider = null
});
注
対称ブロック暗号アルゴリズムのキーの長さは >= 128 ビット、ブロック サイズは >= 64 ビットである必要があります。また、PKCS #7 パディングによる CBC モードの暗号化をサポートする必要があります。 ハッシュ アルゴリズムのダイジェスト サイズは >= 128 ビットである必要があり、BCRYPT_ALG_HANDLE_HMAC_FLAG フラグを使って開かれることをサポートする必要があります。 *Provider プロパティを null に設定すると、指定したアルゴリズムの既定のプロバイダーを使用できます。 詳細については、BCryptOpenAlgorithmProvider に関するドキュメントを参照してください。
Galois/Counter モードの暗号化と検証を使ってカスタムの Windows CNG アルゴリズムを指定するには、アルゴリズム情報を含む CngGcmAuthenticatedEncryptorConfiguration インスタンスを作成します。
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngGcmAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
注
対称ブロック暗号アルゴリズムのキーの長さは >=128 ビット、ブロック サイズはちょうど 128 ビットである必要があります。また、GCM 暗号化をサポートする必要があります。 EncryptionAlgorithmProvider プロパティを null に設定すると、指定したアルゴリズムの既定のプロバイダーを使用できます。 詳細については、BCryptOpenAlgorithmProvider に関するドキュメントを参照してください。
その他のカスタム アルゴリズムの指定
ファーストクラスの API としては公開されていませんが、データ保護システムにはほとんど全種類のアルゴリズムを指定できるようにする拡張性があります。 たとえば、すべてのキーをハードウェア セキュリティ モジュール (HSM) 内で保持し、コアの暗号化および暗号化解除ルーチンのカスタム実装を提供することができます。 詳細については、IAuthenticatedEncryptorに関するページの を参照してください。
Docker コンテナーでホストするときのキーの永続化
Docker コンテナーでホストする場合は、次のいずれかの方法でキーを管理する必要があります。
- 共有ボリュームやホストによってマウントされたボリュームなど、コンテナーの有効期間を超えて永続化される Docker ボリュームのフォルダー。
- 外部プロバイダーとして、Azure Blob Storage(Azure Key Vault でのキーの保護 (
ProtectKeysWithAzureKeyVault
)セクションに示されている)やRedisがあります。
Redis でのキーの永続化
キーの格納には、Redis データ永続化がサポートされている Redis バージョンのみを使う必要があります。 Azure Blob Storage は永続的であり、キーの格納に使用できます。 詳細については、こちらの GitHub の問題のページを参照してください。
ログの記録
問題を診断するには、 Information
以下のレベルのログ記録を有効にします。 次の appsettings.json
ファイルを使用すると、Data Protection API の情報ログが有効になります。
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.DataProtection": "Information"
}
}
}
ログ記録に関する詳細については、「.NET Core と ASP.NET Core でのログ記録」を参照してください。
その他のリソース
ASP.NET Core