ASP.NET Core のコンシューマー API の概要
IDataProtectionProvider
および IDataProtector
インターフェイスは、コンシューマーがデータ保護システムを使うための基本的なインターフェイスです。 これらは Microsoft.AspNetCore.DataProtection.Abstractions パッケージ内にあります。
IDataProtectionProvider
プロバイダー インターフェイスは、データ保護システムのルートを表します。 データの保護または保護解除に直接使うことはできません。 代わりに、コンシューマーは IDataProtectionProvider.CreateProtector(purpose)
を呼び出して IDataProtector
への参照を取得する必要があります。この目的は、意図したコンシューマーのユース ケースを示す文字列です。 このパラメーターの意図と適切な値の選択方法の詳細については、「目的文字列」を参照してください。
IDataProtector
プロテクター インターフェイスは CreateProtector
の呼び出しによって返されます。コンシューマーはこのインターフェイスを使って保護と保護解除の操作を行うことができます。
データの一部を保護するには、Protect
メソッドにデータを渡します。 基本インターフェイスには、byte[] -> byte[] を変換するメソッドが定義されていますが、string -> string を変換するオーバーロードもあります (拡張メソッドとして提供されています)。 この 2 つのメソッドによって提供されるセキュリティは同じです。そのため、開発者はユース ケースに適したオーバーロードを選ぶ必要があります。 どちらのオーバーロードを選んでも、Protect メソッドから返される値は保護されている (暗号化され、改ざんが防止されている) ため、信頼されていないクライアントに対してアプリケーションから送信することができます。
既に保護されているデータの保護を解除するには、保護されているデータを Unprotect
メソッドに渡します (開発者の利便性を考慮して byte[] ベースと文字列ベースのオーバーロードが用意されています)。保護されたペイロードが、この同じ IDataProtector
上の Protect
の以前の呼び出しによって生成された場合、Unprotect
メソッドからは元の保護されていないペイロードが返されます。 保護されたペイロードが改ざんされている場合、または別の IDataProtector
によって生成された場合は、Unprotect
メソッドから CryptographicException がスローされます。
IDataProtector
が同じまたは異なるという概念は、前述の目的の概念につながります。 2 つの IDataProtector
インスタンスが同じルートの IDataProtectionProvider
から生成されても、IDataProtectionProvider.CreateProtector
の呼び出しでは異なる目的文字列を経由した場合、それらは異なるプロテクターと見なされ、いずれかから、もう一方によって生成されたペイロードの保護を解除することはできません。
これらのインターフェイスの使用
DI 対応コンポーネントの場合、コンポーネントがコンストラクターで IDataProtectionProvider
パラメーターを受け取り、コンポーネントのインスタンスが作成されたときに DI システムによって自動的にこのサービスが提供されるという使い方が想定されています。
Note
一部のアプリケーション (コンソール アプリケーションや ASP.NET 4.x アプリケーションなど) は、DI 対応ではないため、ここで説明したメカニズムを使えない場合があります。 このようなシナリオの場合、DI を経由せずに IDataProtection
プロバイダーのインスタンスを取得する方法については、「DI に対応しないシナリオ」のドキュメントを参照してください。
次のサンプルは、3 つの概念を示しています。
DI を使って
IDataProtectionProvider
のインスタンスを受け取る、およびIDataProtectionProvider
からIDataProtector
を作成し、それを使ってデータの保護と保護解除を行う。
コンソール アプリ
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 アプリ
Program.cs
内で AddDataProtection(IServiceCollection, Action<DataProtectionOptions>) を呼び出します:
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
のインスタンスは、複数の呼び出し元に対してスレッドセーフです。 これは、コンポーネントが CreateProtector
への呼び出しによって IDataProtector
への参照を取得すると、その参照が Protect
と Unprotect
の複数の呼び出しに使用されることを意図しています。 保護されたペイロードを検証または解読できない場合、Unprotect
を呼び出すと CryptographicException がスローされます。 一部のコンポーネントでは、保護解除操作中にエラーを無視することが必要な場合があります。認証 cookie を読み取るコンポーネントでは、このエラーを処理し、要求を完全に失敗させるのではなく、cookie がまったくない場合と同様に要求を処理することができます。 この動作を必要とするコンポーネントは、すべての例外を飲み込むのではなく、CryptographicException を明示的にキャッチする必要があります。
ASP.NET Core