Сценарии, не связанные с DI

Система защиты данных обычно добавляется в контейнер сервисов и добавляется в нужные компоненты через механизм DI. Однако в некоторых случаях эта задача невыполнима, обычно при импортировании системы в существующее приложение.

Чтобы поддерживать такие сценарии пакет Microsoft.AspNet.DataProtection.Extensions предоставляет конкретный тип DataProtectionProvider, который предлагает простой способ использования системы защиты данных без DI. Сам тип реализует IDataProtectionProvider, и его создание такое же простое, как и предоставление DirectoryInfo, где хранятся криптографические ключи провайдера.

Например:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
        string destFolder = Path.Combine(
            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: ");
        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: CfDJ8FWbAn6...ch3hAPm1NJA
 * Unprotect returned: Hello world!
 */

Предупреждение

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

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
        string destFolder = Path.Combine(
            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: ");
        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}");
    }
}

Совет

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

Поделись хорошей новостью с друзьями!
Следи за новостями!