Сценарии без поддержки внедрения зависимостей для защиты данных в ASP.NET Core

Автор: Рик Андерсон (Rick Anderson)

Система ASP.NET Core Data Protection обычно добавляется в контейнер службы и используется зависимыми компонентами с помощью внедрения зависимостей (DI). Однако существуют случаи, когда это невозможно или не нужно, особенно при импорте системы в существующее приложение.

Для поддержки этих сценариев пакет Microsoft.AspNetCore.DataProtection.Extensions предоставляет конкретный тип, DataProtectionProviderкоторый предлагает простой способ использования защиты данных без использования di. Тип DataProtectionProvider реализует IDataProtectionProvider. DataProtectionProvider Для создания требуется предоставить DirectoryInfo экземпляр, чтобы указать, где должны храниться криптографические ключи поставщика, как показано в следующем примере кода:

using System;
using System.IO;
using Microsoft.AspNetCore.DataProtection;

public class Program
{
    public static void Main(string[] args)
    {
        // Get the path to %LOCALAPPDATA%\myapp-keys
        var destFolder = Path.Combine(
            System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
            "myapp-keys");

        // Instantiate the data protection system at this folder
        var dataProtectionProvider = DataProtectionProvider.Create(
            new DirectoryInfo(destFolder));

        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        Console.Write("Enter input: ");
        var input = Console.ReadLine();

        // Protect the payload
        var protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");

        // Unprotect the payload
        var unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

        Console.WriteLine();
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Enter input: Hello world!
 * Protect returned: CfDJ8FWbAn6...ch3hAPm1NJA
 * Unprotect returned: Hello world!
 *
 * Press any key...
*/

По умолчанию конкретный DataProtectionProvider тип не шифрует необработанный материал ключа перед сохранением его в файловой системе. Это позволяет поддерживать сценарии, когда разработчик указывает на сетевую папку, а система защиты данных не может автоматически выводить соответствующий механизм шифрования неактивных ключей.

Кроме того, конкретный DataProtectionProvider тип не изолирует приложения по умолчанию. Все приложения, использующие один и тот же каталог ключей, могут совместно использовать полезные данные до тех пор, пока соответствуют их параметрам назначения.

Конструктор DataProtectionProvider принимает необязательный обратный вызов конфигурации, который можно использовать для настройки поведения системы. В приведенном ниже примере показано восстановление изоляции с явным вызовом SetApplicationName. В примере также показано, как настроить систему для автоматического шифрования сохраненных ключей с помощью Windows DPAPI. Если каталог указывает на общую папку UNC, может потребоваться распространить общий сертификат на всех соответствующих компьютерах и настроить систему для использования шифрования на основе сертификатов с вызовом ProtectKeysWithCertificate.

using System;
using System.IO;
using Microsoft.AspNetCore.DataProtection;

public class Program
{
    public static void Main(string[] args)
    {
        // Get the path to %LOCALAPPDATA%\myapp-keys
        var destFolder = Path.Combine(
            System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
            "myapp-keys");

        // Instantiate the data protection system at this folder
        var dataProtectionProvider = DataProtectionProvider.Create(
            new DirectoryInfo(destFolder),
            configuration =>
            {
                configuration.SetApplicationName("my app name");
                configuration.ProtectKeysWithDpapi();
            });

        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        Console.Write("Enter input: ");
        var input = Console.ReadLine();

        // Protect the payload
        var protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");

        // Unprotect the payload
        var unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

        Console.WriteLine();
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }
}

Совет

Экземпляры конкретного DataProtectionProvider типа являются дорогостоящими для создания. Если приложение поддерживает несколько экземпляров этого типа и если они используют один и тот же каталог хранилища ключей, производительность приложения может снизиться. Если вы используете DataProtectionProvider тип, рекомендуется создать этот тип один раз и повторно использовать его как можно больше. DataProtectionProvider Тип и все IDataProtector экземпляры, созданные из него, являются потокобезопасны для нескольких вызывающих.