Cenários sem reconhecimento de DI para a Proteção de Dados no ASP.NET Core
O sistema de proteção de dados do ASP.NET Core normalmente é adicionado a um contêiner de serviço e consumido por componentes dependentes por meio de DI (injeção de dependência). No entanto, há casos em que isso não é viável ou desejado, especialmente ao importar o sistema para um aplicativo existente.
Para dar suporte a esses cenários, o pacote Microsoft.AspNetCore.DataProtection.Extensions fornece um tipo concreto, DataProtectionProvider, que oferece uma maneira simples de usar a proteção de dados sem depender da DI. O tipo DataProtectionProvider
implementa IDataProtectionProvider. A construção de DataProtectionProvider
requer apenas o fornecimento de uma instância DirectoryInfo para indicar onde as chaves criptográficas do provedor devem ser armazenadas, conforme visto no exemplo de código a seguir:
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...
*/
Por padrão, o tipo concreto DataProtectionProvider
não criptografa a matéria-prima da chave antes de mantê-la no sistema de arquivos. Isso é para dar suporte a cenários em que o desenvolvedor aponta para um compartilhamento de rede e o sistema de proteção de dados não consegue deduzir automaticamente um mecanismo de criptografia de chave em rest apropriado.
Além disso, o tipo concreto DataProtectionProvider
não isola aplicativos por padrão. Todos os aplicativos que usam o mesmo diretório de chave podem compartilhar conteúdo desde que os parâmetros de finalidade correspondam.
O construtor DataProtectionProvider aceita um retorno de chamada de configuração opcional que pode ser usado para ajustar os comportamentos do sistema. O exemplo abaixo demonstra a restauração do isolamento com uma chamada explícita para SetApplicationName. O exemplo também demonstra como configurar o sistema para criptografar automaticamente as chaves persistentes usando o DPAPI do Windows. Se o diretório apontar para um compartilhamento UNC, talvez você queira distribuir um certificado compartilhado em todos os computadores relevantes e configurar o sistema para usar a criptografia baseada em certificado com uma chamada para 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();
}
}
Dica
Instâncias do tipo concreto DataProtectionProvider
são caras de criar. Se um aplicativo mantiver várias instâncias desse tipo e se todas estiverem usando o mesmo diretório de armazenamento de chaves, o desempenho do aplicativo poderá ser prejudicado. Se você usar o tipo DataProtectionProvider
, recomendamos que crie esse tipo uma vez e reutilize-o o máximo possível. O tipo DataProtectionProvider
e todas as instâncias IDataProtector criadas com base nele são thread-safe para vários chamadores.