次の方法で共有


ASP.NET Core のコンシューマー API の概要

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 つの概念を示しています。

  1. データ保護システムをサービス コンテナーに追加する、

  2. DI を使って IDataProtectionProvider のインスタンスを受け取る、および

  3. 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}");
    }
}

ヒント

IDataProtectionProviderIDataProtector のインスタンスは、複数の呼び出し元に対してスレッドセーフです。 これは、コンポーネントが IDataProtector への呼び出しによって CreateProtector への参照を取得すると、その参照が ProtectUnprotect の複数の呼び出しに使用されることを意図しています。 保護されたペイロードを検証または解読できない場合、Unprotect を呼び出すと CryptographicException がスローされます。 一部のコンポーネントでは、保護解除操作中にエラーを無視することが必要な場合があります。認証 cookie を読み取るコンポーネントでは、このエラーを処理し、要求を完全に失敗させるのではなく、cookie がまったくない場合と同様に要求を処理することができます。 この動作を必要とするコンポーネントは、すべての例外を飲み込むのではなく、CryptographicException を明示的にキャッチする必要があります。