IDataProtectionProvider および IDataProtector インターフェイスは、コンシューマーがデータ保護システムを使うための基本的なインターフェイスです。 これらは Microsoft.AspNetCore.DataProtection.Abstractions パッケージ内にあります。
IDataProtectionProvider
プロバイダー インターフェイスは、データ保護システムのルートを表します。 データの保護または保護解除に直接使うことはできません。 代わりに、コンシューマーは IDataProtector を呼び出して IDataProtectionProvider.CreateProtector(purpose) への参照を取得する必要があります。この目的は、意図したコンシューマーのユース ケースを示す文字列です。 このパラメーターの意図と適切な値の選択方法の詳細については、「目的文字列」を参照してください。
IDataProtector
プロテクター インターフェイスは CreateProtector の呼び出しによって返されます。コンシューマーはこのインターフェイスを使って保護と保護解除の操作を行うことができます。
データの一部を保護するには、Protect メソッドにデータを渡します。 基本インターフェイスには、byte[] -> byte[] を変換するメソッドが定義されていますが、string -> string を変換するオーバーロードもあります (拡張メソッドとして提供されています)。 この 2 つのメソッドによって提供されるセキュリティは同じです。そのため、開発者はユース ケースに適したオーバーロードを選ぶ必要があります。 どちらのオーバーロードを選んでも、Protect メソッドから返される値は保護されている (暗号化され、改ざんが防止されている) ため、信頼されていないクライアントに対してアプリケーションから送信することができます。
既に保護されているデータの保護を解除するには、保護されているデータを Unprotect メソッドに渡します (開発者の利便性を考慮して byte[] ベースと文字列ベースのオーバーロードが用意されています)。保護されたペイロードが、この同じ Protect 上の IDataProtector の以前の呼び出しによって生成された場合、Unprotect メソッドからは元の保護されていないペイロードが返されます。 保護されたペイロードが改ざんされている場合、または別の IDataProtector によって生成された場合は、Unprotect メソッドから CryptographicException がスローされます。
IDataProtector が同じまたは異なるという概念は、前述の目的の概念につながります。 2 つの IDataProtector インスタンスが同じルートの IDataProtectionProvider から生成されても、IDataProtectionProvider.CreateProtector の呼び出しでは異なる目的文字列を経由した場合、それらは異なるプロテクターと見なされ、いずれかから、もう一方によって生成されたペイロードの保護を解除することはできません。
これらのインターフェイスの使用
DI 対応コンポーネントの場合、コンポーネントがコンストラクターで IDataProtectionProvider パラメーターを受け取り、コンポーネントのインスタンスが作成されたときに DI システムによって自動的にこのサービスが提供されるという使い方が想定されています。
Note
一部のアプリケーション (コンソール アプリケーションや ASP.NET 4.x アプリケーションなど) は、DI 対応ではないため、ここで説明したメカニズムを使えない場合があります。 このようなシナリオの場合、DI を経由せずに プロバイダーのインスタンスを取得する方法については、「IDataProtection」のドキュメントを参照してください。
次のサンプルは、3 つの概念を示しています。
DI を使って
IDataProtectionProviderのインスタンスを受け取る、およびIDataProtectorからIDataProtectionProviderを作成し、それを使ってデータの保護と保護解除を行う。
コンソール アプリ
using System;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;
public class Program
{
public static void Main(string[] args)
{
// add data protection services
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection();
var services = serviceCollection.BuildServiceProvider();
// create an instance of MyClass using the service provider
var instance = ActivatorUtilities.CreateInstance<MyClass>(services);
instance.RunSample();
}
public class MyClass
{
IDataProtector _protector;
// the 'provider' parameter is provided by DI
public MyClass(IDataProtectionProvider provider)
{
_protector = provider.CreateProtector("Contoso.MyClass.v1");
}
public void RunSample()
{
Console.Write("Enter input: ");
string input = Console.ReadLine();
// protect the payload
string protectedPayload = _protector.Protect(input);
Console.WriteLine($"Protect returned: {protectedPayload}");
// unprotect the payload
string unprotectedPayload = _protector.Unprotect(protectedPayload);
Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
}
}
}
/*
* SAMPLE OUTPUT
*
* Enter input: Hello world!
* Protect returned: CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ
* Unprotect returned: Hello world!
*/
Web アプリ
AddDataProtection(IServiceCollection, Action<DataProtectionOptions>) 内で Program.cs を呼び出します:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDataProtection();
var app = builder.Build();
次の強調表示されたコードは、コントローラーでの IDataProtector を使用する方法を示しています:
public class HomeController : Controller
{
private readonly IDataProtector _dataProtector;
public HomeController(IDataProtectionProvider dataProtectionProvider)
{
_dataProtector = dataProtectionProvider.CreateProtector("HomeControllerPurpose");
}
// ...
public IActionResult Privacy()
{
// The original data to protect
string originalData = "original data";
// Protect the data (encrypt)
string protectedData = _dataProtector.Protect(originalData);
Console.WriteLine($"Protected Data: {protectedData}");
// Unprotect the data (decrypt)
string unprotectedData = _dataProtector.Unprotect(protectedData);
Console.WriteLine($"Unprotected Data: {unprotectedData}");
return View();
}
// ...
パッケージ Microsoft.AspNetCore.DataProtection.Abstractions には開発者の便宜のため拡張メソッド GetDataProtector が含まれています。 これには、サービス プロバイダーから IDataProtectionProvider を取得することと IDataProtectionProvider.CreateProtector を呼び出すことが 1 つの操作としてカプセル化されています。 次のサンプルは、この使用例を示しています:
using System;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;
public class Program
{
public static void Main(string[] args)
{
// add data protection services
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection();
var services = serviceCollection.BuildServiceProvider();
// get an IDataProtector from the IServiceProvider
var protector = services.GetDataProtector("Contoso.Example.v2");
Console.Write("Enter input: ");
string input = Console.ReadLine();
// protect the payload
string protectedPayload = protector.Protect(input);
Console.WriteLine($"Protect returned: {protectedPayload}");
// unprotect the payload
string unprotectedPayload = protector.Unprotect(protectedPayload);
Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
}
}
ヒント
IDataProtectionProvider と IDataProtector のインスタンスは、複数の呼び出し元に対してスレッドセーフです。 これは、コンポーネントが IDataProtector への呼び出しによって CreateProtector への参照を取得すると、その参照が Protect と Unprotect の複数の呼び出しに使用されることを意図しています。 保護されたペイロードを検証または解読できない場合、Unprotect を呼び出すと CryptographicException がスローされます。 一部のコンポーネントでは、保護解除操作中にエラーを無視することが必要な場合があります。認証 cookie を読み取るコンポーネントでは、このエラーを処理し、要求を完全に失敗させるのではなく、cookie がまったくない場合と同様に要求を処理することができます。 この動作を必要とするコンポーネントは、すべての例外を飲み込むのではなく、CryptographicException を明示的にキャッチする必要があります。
ASP.NET Core