非 DI 感知的情境中 ASP.NET Core 的数据保护Non-DI aware scenarios for Data Protection in ASP.NET Core

本文内容

作者:Rick Anderson

ASP.NET Core 数据保护系统通常会添加到服务容器中,并通过依赖关系注入(DI)由从属组件使用。但是,在某些情况下,这种情况并不可行,尤其是将系统导入现有应用时。

为了支持这些方案, AspNetCore包提供了一个具体类型DataProtectionProvider,这提供了一种简单的方法来使用数据保护,而无需依赖于 DI。DataProtectionProvider 类型实现IDataProtectionProvider构造 DataProtectionProvider 仅要求提供DirectoryInfo实例以指示应在何处存储提供程序的加密密钥,如以下代码示例所示:

  1. using System;
  2. using System.IO;
  3. using Microsoft.AspNetCore.DataProtection;
  4. public class Program
  5. {
  6. public static void Main(string[] args)
  7. {
  8. // Get the path to %LOCALAPPDATA%\myapp-keys
  9. var destFolder = Path.Combine(
  10. System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
  11. "myapp-keys");
  12. // Instantiate the data protection system at this folder
  13. var dataProtectionProvider = DataProtectionProvider.Create(
  14. new DirectoryInfo(destFolder));
  15. var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
  16. Console.Write("Enter input: ");
  17. var input = Console.ReadLine();
  18. // Protect the payload
  19. var protectedPayload = protector.Protect(input);
  20. Console.WriteLine($"Protect returned: {protectedPayload}");
  21. // Unprotect the payload
  22. var unprotectedPayload = protector.Unprotect(protectedPayload);
  23. Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
  24. Console.WriteLine();
  25. Console.WriteLine("Press any key...");
  26. Console.ReadKey();
  27. }
  28. }
  29. /*
  30. * SAMPLE OUTPUT
  31. *
  32. * Enter input: Hello world!
  33. * Protect returned: CfDJ8FWbAn6...ch3hAPm1NJA
  34. * Unprotect returned: Hello world!
  35. *
  36. * Press any key...
  37. */

默认情况下,DataProtectionProvider 具体类型不会在将原始密钥材料保存到文件系统之前对其进行加密。这是为了支持开发人员指向网络共享的情况,并且数据保护系统无法自动推导适当的静止密钥加密机制。

此外,默认情况下,DataProtectionProvider 具体类型不会隔离应用只要其用途参数匹配,使用同一密钥目录的所有应用都可以共享有效负载。

DataProtectionProvider构造函数接受可用于调整系统行为的可选配置回调。下面的示例演示如何使用对SetApplicationName的显式调用来还原隔离。该示例还演示了如何将系统配置为使用 Windows DPAPI 自动加密保留密钥。如果目录指向 UNC 共享,你可能希望在所有相关的计算机上分发共享证书,并将系统配置为使用基于证书的加密,并调用ProtectKeysWithCertificate

  1. using System;
  2. using System.IO;
  3. using Microsoft.AspNetCore.DataProtection;
  4. public class Program
  5. {
  6. public static void Main(string[] args)
  7. {
  8. // Get the path to %LOCALAPPDATA%\myapp-keys
  9. var destFolder = Path.Combine(
  10. System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
  11. "myapp-keys");
  12. // Instantiate the data protection system at this folder
  13. var dataProtectionProvider = DataProtectionProvider.Create(
  14. new DirectoryInfo(destFolder),
  15. configuration =>
  16. {
  17. configuration.SetApplicationName("my app name");
  18. configuration.ProtectKeysWithDpapi();
  19. });
  20. var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
  21. Console.Write("Enter input: ");
  22. var input = Console.ReadLine();
  23. // Protect the payload
  24. var protectedPayload = protector.Protect(input);
  25. Console.WriteLine($"Protect returned: {protectedPayload}");
  26. // Unprotect the payload
  27. var unprotectedPayload = protector.Unprotect(protectedPayload);
  28. Console.WriteLine($"Unprotect returned: {unprotectedPayload}");
  29. Console.WriteLine();
  30. Console.WriteLine("Press any key...");
  31. Console.ReadKey();
  32. }
  33. }

提示

创建的 DataProtectionProvider 具体类型的实例成本很高。如果应用维护该类型的多个实例,并且它们都使用相同的密钥存储目录,应用性能可能会降低。如果你使用 DataProtectionProvider 类型,则建议你创建此类型一次并尽可能重复使用。DataProtectionProvider 类型和从该类型创建的所有IDataProtector实例对于多个调用方是线程安全的。