Compartilhar via


Configurar a proteção de dados do ASP.NET Core

Quando o sistema de Proteção de Dados é inicializado, ele aplica as configurações padrão com base no ambiente operacional. Essas configurações são apropriadas para aplicativos em execução em um único computador. No entanto, há casos em que um desenvolvedor pode querer alterar as configurações padrão:

  • O aplicativo é distribuído em vários computadores.
  • Por motivos de conformidade.

Para esses cenários, o sistema de Proteção de Dados oferece uma API de configuração avançada.

Warning

Semelhante aos arquivos de configuração, o anel de chave de proteção de dados deve ser protegido usando as permissões apropriadas. Você pode optar por criptografar chaves em repouso, mas isso não impede que os ciberataques criem novas chaves. Consequentemente a segurança do aplicativo é afetada. O local de armazenamento configurado com a Proteção de Dados deve ter seu acesso limitado ao próprio aplicativo, semelhante à maneira como você protegeria os arquivos de configuração. Por exemplo, se você optar por armazenar seu anel de chaves no disco, use permissões do sistema de arquivos. Certifique-se de que apenas a identidade sob a qual seu aplicativo web é executado tenha acesso de leitura, gravação e criação a esse diretório. Se você usar o Armazenamento de Blobs do Azure, somente o aplicativo Web deverá ter a capacidade de ler, gravar ou criar novas entradas no repositório de blobs etc.

O método de extensão AddDataProtection retorna um IDataProtectionBuilder. IDataProtectionBuilder expõe métodos de extensão que você pode encadear para configurar opções de Proteção de Dados.

Note

Este artigo foi escrito para um aplicativo que é executado em um contêiner de janela de encaixe. Em um contêiner do Docker, o aplicativo sempre tem o mesmo caminho e, portanto, o mesmo discriminador de aplicativos. Os aplicativos que precisam ser executados em vários ambientes (por exemplo, local e implantado) devem definir o discriminador de aplicações padrão para o ambiente. A execução de um aplicativo em vários ambientes está além do escopo deste artigo.

Os seguintes pacotes NuGet são necessários para as extensões de Proteção de Dados usadas neste artigo:

Proteger chaves com o Azure Key Vault (ProtectKeysWithAzureKeyVault)

Para interagir com o Azure Key Vault localmente usando credenciais de desenvolvedor, entre em sua conta de armazenamento no Visual Studio ou entre com a CLI do Azure. Se você ainda não instalou a CLI do Azure, confira Como instalar a CLI do Azure. Você pode executar o seguinte comando no painel do PowerShell do Desenvolvedor no Visual Studio ou em um shell de comando ao não usar o Visual Studio:

az login

Para obter mais informações, consulte Entrar no Azure usando ferramentas de desenvolvedor.

Ao configurar o cofre de chaves no portal do Entra ou Azure:

  • Configure o cofre de chaves para usar o RABC (controle de acesso baseado em função) do Azure. Se você não estiver operando em uma Rede Virtual do Azure, inclusive para desenvolvimento local e teste, confirme se o acesso público na etapa rede está habilitado (verificado). A habilitação do acesso público só expõe o ponto de extremidade do cofre de chaves. Contas autenticadas ainda são necessárias para acesso.

  • Crie um Recurso Gerenciado do Azure Identity (ou adicione uma função ao Recurso Gerenciado Identity existente que você planeja usar) com a função de Usuário de Criptografia do Key Vault. Atribua o Identity Gerenciado ao Serviço de Aplicativo do Azure que está hospedando a implantação: Configurações>Identity>Atribuído pelo usuário>Adicionar.

    Note

    Se você também planeja executar um aplicativo localmente com um usuário autorizado para acesso a blobs usando a CLI do Azure ou a Autenticação do Serviço do Azure do Visual Studio, adicione sua conta de usuário do Azure para desenvolvedor no Controle de Acesso (IAM) com a função Usuário Cripto do Key Vault. Se você quiser usar a CLI do Azure por meio do Visual Studio, execute o az login comando no painel do PowerShell do Desenvolvedor e siga os prompts para autenticar com o locatário.

  • Quando a criptografia de chave estiver ativa, as chaves no arquivo de chave incluem o comentário "This key is encrypted with Azure Key Vault." Depois de iniciar o aplicativo, selecione o comando Exibir/editar no menu de contexto no final da linha de chave para confirmar se uma chave está presente com a segurança do cofre de chaves aplicada.

  • Você também pode habilitar o rodízio automático de chaves do cofre de chaves sem se preocupar em descriptografar cargas com chaves de proteção de dados com base em chaves expiradas/giradas do cofre de chaves. Cada chave de proteção de dados gerada inclui uma referência à chave do cofre de chaves usada para criptografá-la. Apenas certifique-se de manter as chaves expiradas no cofre de chaves, não as exclua. Além disso, use um identificador de chave sem versão na configuração do cofre de chaves do aplicativo, onde o GUID da chave não é adicionado ao final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection). Use um período de rotação semelhante para ambas as chaves com a chave do cofre de chaves girando com mais frequência do que a chave de proteção de dados para garantir que uma nova chave do cofre de chaves seja usada no momento da rotação da chave de proteção de dados.

Proteger chaves com o Azure Key Vault implementa um IXmlEncryptor que desabilita as configurações automáticas de proteção de dados, incluindo o local de armazenamento do anel de chaves. Para configurar o provedor de Armazenamento de Blobs do Azure para armazenar as chaves no armazenamento de blobs, siga as orientações em Provedores de armazenamento de chaves no ASP.NET Core e utilize uma das PersistKeysToAzureBlobStorage sobrecargas no aplicativo. O seguinte exemplo utiliza a sobrecarga que aceita um URI de blob e uma credencial de token (TokenCredential), contando com um Identity Gerenciado do Azure para controle de acesso baseado em função (RBAC).

Para configurar o provedor do Azure Key Vault, chame uma das sobrecargas ProtectKeysWithAzureKeyVault. O exemplo a seguir usa a sobrecarga que aceita o identificador de chave e a credencial de token (TokenCredential), contando com um Gerenciado Identity para RBAC em produção (ManagedIdentityCredential) ou um DefaultAzureCredential durante o desenvolvimento e teste. Outras sobrecargas aceitam um cliente de cofre de chaves ou um ID de cliente do aplicativo com segredo de cliente. Para obter mais informações, veja Principais provedores de armazenamento no ASP.NET Core.

Para obter mais informações sobre a API e a autenticação do SDK do Azure, consulte Autenticar aplicativos .NET nos serviços do Azure usando a biblioteca do Azure Identity e fornecer acesso a chaves, certificados e segredos do Key Vault com o controle de acesso baseado em função do Azure. Para obter orientações sobre logs, consulte Log com o SDK do Azure para .NET: log sem registro do cliente. Para aplicativos que usam injeção de dependência, um aplicativo pode chamar AddAzureClientsCore, passando true para enableLogForwarding, para criar e conectar a infraestrutura de log.

Para criar uma chave no portal do Azure, consulte Início Rápido: Definir e recuperar uma chave do Azure Key Vault usando o portal do Azure. Dê a chave, pelo menos Get, Unwrap Keye Wrap Key permissões. Registre o identificador de chave para uso com a configuração do aplicativo. Se você planeja habilitar a rotação automática da chave do cofre de chaves, registre o identificador de chave sem versão específica, onde não há um GUID de chave colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

No arquivo Program onde os serviços são registrados:

TokenCredential? credential;

if (builder.Environment.IsProduction())
{
    credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
    // Local development and testing only
    DefaultAzureCredentialOptions options = new()
    {
        // Specify the tenant ID to use the dev credentials when running the app locally
        // in Visual Studio.
        VisualStudioTenantId = "{TENANT ID}",
        SharedTokenCacheTenantId = "{TENANT ID}"
    };

    credential = new DefaultAzureCredential(options);
}

builder.Services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

{MANAGED IDENTITY CLIENT ID}: o ID do cliente gerenciado do Azure Identity (GUID).

{TENANT ID}: ID do locatário.

{APPLICATION NAME}: SetApplicationName define o nome exclusivo desse aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre implantações do aplicativo.

{BLOB URI}: URI completo para o arquivo de chave. O URI é gerado pelo Armazenamento do Azure quando você cria o arquivo de chave. Não use um SAS.

{KEY IDENTIFIER}: identificador de chave do Azure Key Vault usado para criptografia de chave. Uma política de acesso permite que o aplicativo acesse o cofre de chaves com Get, Unwrap Keye Wrap Key permissões. A versão da chave é obtida da chave no portal do Entra ou do Azure depois que ela é criada. Se você habilitar a rotação automática da chave do cofre de chaves, certifique-se de usar um identificador de chave sem versão na configuração do cofre de chaves do aplicativo, em que o GUID de chave não é colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

Para que um aplicativo se comunique e se autorize com o Azure Key Vault, o Azure.Identity pacote NuGet deve ser referenciado pelo aplicativo.

Note

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Note

Em ambientes que não utilizam Production, o exemplo anterior usa DefaultAzureCredential para simplificar a autenticação ao desenvolver aplicativos que são implantados no Azure, combinando as credenciais usadas nos ambientes de hospedagem do Azure com as credenciais usadas no desenvolvimento local. Para obter mais informações, consulte Autenticar aplicativos .NET hospedados no Azure em recursos do Azure usando uma identidade gerenciada atribuída pelo sistema.

Se o aplicativo usar os pacotes mais antigos do Azure (Microsoft.AspNetCore.DataProtection.AzureStorage e Microsoft.AspNetCore.DataProtection.AzureKeyVault), recomendamos remover essas referências e atualizar para os pacotes Azure.Extensions.AspNetCore.DataProtection.Blobs e Azure.Extensions.AspNetCore.DataProtection.Keys. Os pacotes mais recentes abordam problemas principais de segurança e estabilidade.

Abordagem alternativa de SAS (assinatura de acesso compartilhado): como alternativa ao uso de um recurso gerenciado Identity para acessar o blob de chaves no Armazenamento de Blobs do Azure, você pode chamar a sobrecarga PersistKeysToAzureBlobStorage que aceita um URI de blob com um token SAS. O exemplo a seguir continua a usar um ManagedIdentityCredential (produção) ou DefaultAzureCredential (desenvolvimento e teste) para seu TokenCredential, como visto no exemplo anterior:

builder.Services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

{APPLICATION NAME}: SetApplicationName define o nome exclusivo desse aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre implantações do aplicativo.

{BLOB URI WITH SAS}: o URI completo em que o arquivo de chave deve ser armazenado com o token SAS como um parâmetro de cadeia de caracteres de consulta. O URI é gerado pelo Armazenamento do Azure quando você solicita uma SAS para o arquivo de chave carregado.

{KEY IDENTIFIER}: identificador de chave do Azure Key Vault usado para criptografia de chave. Uma política de acesso permite que o aplicativo acesse o cofre de chaves com Get, Unwrap Keye Wrap Key permissões. A versão da chave é obtida da chave no portal do Entra ou do Azure depois que ela é criada. Caso você habilite o rodízio automático da chave do cofre de chaves, certifique-se de usar um identificador de chave sem versão na configuração do cofre de chaves do aplicativo, onde nenhum GUID de chave é colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

Manter chaves para o sistema de arquivos (PersistKeysToFileSystem)

Para armazenar chaves em um compartilhamento UNC em vez de no local padrão %LOCALAPPDATA%, configure o sistema com PersistKeysToFileSystem:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));

Warning

Se você alterar o local de persistência de chave, o sistema não criptografará mais automaticamente as chaves em repouso, pois ele não sabe se o DPAPI é um mecanismo de criptografia apropriado.

Manter chaves em um banco de dados (PersistKeysToDbContext)

Para armazenar chaves em um banco de dados usando EntityFramework, configure o sistema com o pacote Microsoft.AspNetCore.DataProtection.EntityFrameworkCore :

builder.Services.AddDataProtection()
    .PersistKeysToDbContext<SampleDbContext>();

O código anterior armazena as chaves no banco de dados configurado. O contexto de banco de dados que está sendo usado deve implementar IDataProtectionKeyContext. IDataProtectionKeyContext expõe a propriedade DataProtectionKeys

public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;

Essa propriedade representa a tabela na qual as chaves são armazenadas. Crie a tabela manualmente ou com Migrações DbContext. Para obter mais informações, consulte DataProtectionKey.

API de configuração de chaves de proteção (ProtectKeysWith\*)

Você pode configurar o sistema para proteger chaves em repouso chamando qualquer uma das ProtectKeysWith\* APIs de configuração. Considere o exemplo abaixo, que armazena chaves em um compartilhamento UNC e criptografa essas chaves em repouso com um certificado X.509 específico.

Você pode fornecer um X509Certificate2 para ProtectKeysWithCertificate de um arquivo chamando X509CertificateLoader.LoadCertificateFromFile:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .ProtectKeysWithCertificate(
        new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));

O exemplo de código a seguir demonstra como carregar um certificado usando uma impressão digital:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);

Você pode fornecer um X509Certificate2 para ProtectKeysWithCertificate, como um certificado carregado de um arquivo:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .ProtectKeysWithCertificate(
        new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));

O exemplo de código a seguir demonstra como carregar um certificado usando uma impressão digital:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);

Para obter exemplos e discussões sobre os mecanismos de criptografia de chave internos, consulte a criptografia de chave em repouso no Windows e no Azure usando ASP.NET Core.

Desproteger chaves com qualquer certificado (UnprotectKeysWithAnyCertificate)

Você pode girar certificados e descriptografar chaves em repouso usando uma matriz de certificados X509Certificate2 com UnprotectKeysWithAnyCertificate:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .ProtectKeysWithCertificate(
        new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]))
    .UnprotectKeysWithAnyCertificate(
        new X509Certificate2("certificate_1.pfx", builder.Configuration["CertificatePassword_1"]),
        new X509Certificate2("certificate_2.pfx", builder.Configuration["CertificatePassword_2"]));

Definir o tempo de vida da chave padrão (SetDefaultKeyLifetime)

Para configurar o sistema para usar um tempo de vida de chave de 14 dias em vez dos 90 dias padrão, use SetDefaultKeyLifetime:

builder.Services.AddDataProtection()
    .SetDefaultKeyLifetime(TimeSpan.FromDays(14));

Definir o nome do aplicativo (SetApplicationName)

Por padrão, o sistema de Proteção de Dados isola os aplicativos uns dos outros com base em seus caminhos de raiz de conteúdo , mesmo que compartilhem o mesmo repositório de chaves físicas. Esse isolamento impede que os aplicativos compreendam os conteúdos protegidos uns dos outros.

Para compartilhar cargas protegidas entre aplicativos:

builder.Services.AddDataProtection()
    .SetApplicationName("<sharedApplicationName>");

SetApplicationName define DataProtectionOptions.ApplicationDiscriminator internamente. Para fins de solução de problemas, o valor atribuído ao discriminador pela estrutura pode ser registrado com o seguinte código colocado depois que o WebApplication é interno:Program.cs

var discriminator = app.Services.GetRequiredService<IOptions<DataProtectionOptions>>()
    .Value.ApplicationDiscriminator;
app.Logger.LogInformation("ApplicationDiscriminator: {ApplicationDiscriminator}", discriminator);

Para obter mais informações sobre como o discriminador é usado, consulte as seguintes seções mais adiante nesse artigo:

Warning

No .NET 6, WebApplicationBuilder normaliza o caminho raiz do conteúdo para terminar com um DirectorySeparatorChar. Por exemplo, no Windows, o caminho raiz do conteúdo termina em \ e no Linux /. Outros hosts não normalizam o caminho. A maioria dos aplicativos que migram de HostBuilder ou WebHostBuilder não compartilham o mesmo nome de aplicativo porque não terão o encerramento DirectorySeparatorChar. Para contornar esse problema, remova o caractere separador de diretório e defina o nome do aplicativo manualmente, conforme mostrado no código a seguir:

using System.Reflection;
using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

var trimmedContentRootPath = 
    builder.Environment.ContentRootPath.TrimEnd(Path.DirectorySeparatorChar);

builder.Services.AddDataProtection().SetApplicationName(trimmedContentRootPath);

var app = builder.Build();

app.MapGet("/", () => Assembly.GetEntryAssembly()!.GetName().Name);

app.Run();

Desabilitar a geração automática de chaves (DisableAutomaticKeyGeneration)

Você pode ter um cenário em que não deseja que um aplicativo role automaticamente as chaves (criar novas chaves) à medida que elas se aproximam da expiração. Um exemplo desse cenário pode ser aplicativos configurados em uma relação primária/secundária, em que apenas o aplicativo primário é responsável por questões de gerenciamento de chaves e os aplicativos secundários simplesmente têm uma exibição somente leitura do anel de chaves. Os aplicativos secundários podem ser configurados para tratar o anel de chave como somente leitura configurando o sistema com DisableAutomaticKeyGeneration:

builder.Services.AddDataProtection()
    .DisableAutomaticKeyGeneration();

Isolamento por aplicativo

Quando o sistema de Proteção de Dados é fornecido por um host ASP.NET Core, ele isola automaticamente os aplicativos uns dos outros, mesmo que esses aplicativos estejam em execução na mesma conta de processo de trabalho e estejam usando o mesmo material de chave mestra. Isso é semelhante ao modificador IsolateApps do elemento system.web <machineKey> .

O mecanismo de isolamento funciona considerando cada aplicativo no computador local como um locatário exclusivo, portanto, o root IDataProtector para qualquer aplicativo específico inclui automaticamente a ID do aplicativo como um discriminador (ApplicationDiscriminator). A ID exclusiva do aplicativo é o caminho físico do aplicativo:

  • Para aplicativos hospedados no IIS, a ID exclusiva é o caminho físico do IIS do aplicativo. Se um aplicativo for implantado em um ambiente de Web farm, esse valor será estável supondo que os ambientes do IIS sejam configurados da mesma forma em todos os computadores no Web farm.
  • Para aplicativos auto-hospedados em execução no Kestrel servidor, a ID exclusiva é o caminho físico para o aplicativo no disco.

O identificador exclusivo foi projetado para sobreviver às redefinições, tanto do aplicativo individual quanto do próprio computador.

Esse mecanismo de isolamento pressupõe que os aplicativos não são mal-intencionados. Um aplicativo mal-intencionado sempre pode afetar qualquer outro aplicativo em execução na mesma conta de processo de trabalho. Em um ambiente de hospedagem compartilhado em que os aplicativos são mutuamente não confiáveis, o provedor de hospedagem deve tomar medidas para garantir o isolamento no nível do sistema operacional entre aplicativos, incluindo a separação dos repositórios de chaves subjacentes dos aplicativos.

Se o sistema de Proteção de Dados não for fornecido por um host ASP.NET Core (por exemplo, se você instanciá-lo por meio do tipo concreto do DataProtectionProvider), o isolamento do aplicativo será desabilitado por padrão. Quando o isolamento do aplicativo é desabilitado, todos os aplicativos apoiados pelo mesmo material de chave podem compartilhar cargas, desde que forneçam as finalidades apropriadas. Para fornecer isolamento de aplicativo nesse ambiente, chame o método SetApplicationName no objeto de configuração e forneça um nome exclusivo para cada aplicativo.

Proteção de dados e isolamento de aplicativo

Considere os seguintes pontos para isolamento do aplicativo:

  • Quando vários aplicativos são apontados para o mesmo repositório de chaves, a intenção é que os aplicativos compartilhem o mesmo material de chave mestra. A Proteção de Dados é desenvolvida com a suposição de que todos os aplicativos que compartilham um anel de chaves podem acessar todos os itens nesse anel de chave. O identificador exclusivo do aplicativo é usado para isolar chaves específicas do aplicativo derivadas das chaves fornecidas pelo anel de chaves. Ele não espera que permissões de nível de item, como as fornecidas pelo Azure KeyVault, sejam usadas para impor isolamento extra. A tentativa de permissões no nível do item gera erros de aplicativo. Se você não quiser contar com o isolamento interno do aplicativo, os locais de repositório de chaves separados devem ser usados e não compartilhados entre aplicativos.

  • O aplicativo discriminatório (ApplicationDiscriminator) é usado para permitir que diferentes aplicativos compartilhem o mesmo material de chave mestra, mas para manter suas cargas criptográficas distintas umas das outras. Para que os aplicativos possam ler as cargas criptográficas uns dos outros, eles devem ter o mesmo discriminador de aplicativo, que pode ser definido chamando SetApplicationName.

  • Se um aplicativo estiver comprometido (por exemplo, por um ataque RCE), todo o material de chave mestra acessível a esse aplicativo também deverá ser considerado comprometido, independentemente de seu estado de proteção em repouso. Isso implica que, se dois aplicativos forem apontados para o mesmo repositório, mesmo que usem discriminadores de aplicativo diferentes, o comprometimento de um deles será funcionalmente equivalente ao comprometimento de ambos.

    Essa cláusula "funcionalmente equivalente a um comprometimento de ambos" é mantida mesmo que os dois aplicativos usem mecanismos diferentes para proteção de chave em repouso. Normalmente, essa não é uma configuração esperada. O mecanismo de proteção de dados em repouso destina-se a fornecer proteção caso um ciberatacante obtenha acesso de leitura ao repositório. Um invasor cibernético que obtém acesso de gravação ao repositório (talvez porque alcançou a permissão de execução de código em um aplicativo) pode inserir chaves mal-intencionadas no armazenamento. O sistema de proteção de dados intencionalmente não fornece proteção contra um invasor cibernético que obtém acesso de gravação ao repositório de chaves.

  • Se os aplicativos precisarem permanecer verdadeiramente isolados uns dos outros, eles deverão usar repositórios de chaves diferentes. Isso naturalmente sai da definição de "isolado". Os aplicativos não serão isolados se todos tiverem acesso de Leitura e Gravação aos armazenamentos de dados uns dos outros.

Como alterar algoritmos com UseCryptographicAlgorithms

A pilha de Proteção de Dados permite que você altere o algoritmo padrão usado pelas chaves recém-geradas. A maneira mais simples de fazer isso é chamar UseCryptographicAlgorithms do retorno de chamada de configuração:

builder.Services.AddDataProtection()
    .UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
    {
        EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
        ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
    });

O EncryptionAlgorithm padrão é AES-256-CBC e o Padrão ValidationAlgorithm é HMACSHA256. A política padrão pode ser definida por um administrador do sistema por meio de uma política de todo o computador, mas uma chamada explícita para UseCryptographicAlgorithms substituir a política padrão.

Chamar UseCryptographicAlgorithms permite que você especifique o algoritmo desejado de uma lista interna predefinida. Você não precisa se preocupar com os detalhes de implementação do algoritmo. No cenário acima, o sistema de Proteção de Dados tenta usar a implementação de CNG do AES se estiver em execução no Windows. Caso contrário, ele voltará para a classe gerenciada System.Security.Cryptography.Aes .

Você pode especificar manualmente uma implementação por meio de uma chamada para UseCustomCryptographicAlgorithms.

Tip

A alteração de algoritmos não afeta as chaves existentes no anel de chave. Ela afeta apenas as chaves recém-geradas.

Especificando algoritmos gerenciados personalizados

Para especificar algoritmos gerenciados personalizados, crie uma instância ManagedAuthenticatedEncryptorConfiguration que aponte para os tipos de implementação:

builder.Services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(new ManagedAuthenticatedEncryptorConfiguration
    {
        // A type that subclasses SymmetricAlgorithm
        EncryptionAlgorithmType = typeof(Aes),

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

        // A type that subclasses KeyedHashAlgorithm
        ValidationAlgorithmType = typeof(HMACSHA256)
    });

Geralmente, as propriedades *Type devem apontar para implementações concretas e instanciáveis (por meio de um ctor sem parâmetros público) de SymmetricAlgorithm e KeyedHashAlgorithm, embora o sistema especialmente case alguns valores, como typeof(Aes) para conveniência.

Note

O SymmetricAlgorithm deve ter um comprimento de chave de ≥ 128 bits e um tamanho de bloco de ≥ 64 bits e deve dar suporte à criptografia do modo CBC com preenchimento PKCS nº 7. O KeyedHashAlgorithm deve ter um tamanho de resumo de >= 128 bits e deve dar suporte a chaves de comprimento iguais ao comprimento de resumo do algoritmo de hash. O KeyedHashAlgorithm não é estritamente necessário para ser HMAC.

Especificando algoritmos CNG personalizados do Windows

Para especificar um algoritmo CNG personalizado do Windows usando a criptografia do modo CBC com validação HMAC, crie uma instância CngCbcAuthenticatedEncryptorConfiguration que contenha as informações algorítmicas:

builder.Services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(new CngCbcAuthenticatedEncryptorConfiguration
    {
        // Passed to BCryptOpenAlgorithmProvider
        EncryptionAlgorithm = "AES",
        EncryptionAlgorithmProvider = null,

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

        // Passed to BCryptOpenAlgorithmProvider
        HashAlgorithm = "SHA256",
        HashAlgorithmProvider = null
    });

Note

O algoritmo de criptografia de bloco simétrico deve ter um comprimento de chave de >= 128 bits e um tamanho de bloco de >= 64 bits e deve dar suporte à criptografia do modo CBC com preenchimento PKCS nº 7. O algoritmo de hash deve ter um tamanho de resumo de >= 128 bits e deve dar suporte à abertura com o sinalizador BCRYPT_ALG_HANDLE_HMAC_FLAG. As propriedades *Provider podem ser definidas como nulas para usar o provedor padrão para o algoritmo especificado. Para obter mais informações, consulte a documentação BCryptOpenAlgorithmProvider.

Para especificar um algoritmo CNG personalizado do Windows usando a criptografia do modo Galois/Counter com validação, crie uma instância CngGcmAuthenticatedEncryptorConfiguration que contenha as informações algorítmicas:

builder.Services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(new CngGcmAuthenticatedEncryptorConfiguration
    {
        // Passed to BCryptOpenAlgorithmProvider
        EncryptionAlgorithm = "AES",
        EncryptionAlgorithmProvider = null,

        // Specified in bits
        EncryptionAlgorithmKeySize = 256
    });

Note

O algoritmo de criptografia de bloco simétrico deve ter um comprimento de chave de >=128 bits, um tamanho de bloco de 128 bits e deve dar suporte à criptografia GCM. Você pode definir a propriedade EncryptionAlgorithmProvider como nula para usar o provedor padrão para o algoritmo especificado. Para obter mais informações, consulte a documentação BCryptOpenAlgorithmProvider.

Especificando outros algoritmos personalizados

Embora não seja exposto como uma API de primeira classe, o sistema de Proteção de Dados é extensível o suficiente para permitir a especificação de quase qualquer tipo de algoritmo. Por exemplo, é possível manter todas as chaves contidas em um HSM (Módulo de Segurança de Hardware) e fornecer uma implementação personalizada das principais rotinas de criptografia e descriptografia. Para obter mais informações, consulte IAuthenticatedEncryptor em Extensibilidade de criptografia principal.

Chaves persistentes ao hospedar em um contêiner do Docker

Ao hospedar em um contêiner do Docker, as chaves devem ser mantidas em:

Teclas persistentes com Redis

Somente as versões do Redis que dão suporte à Persistência de Dados Redis devem ser usadas para armazenar chaves. O Armazenamento de Blobs do Azure é persistente e pode ser usado para armazenar chaves. Para obter mais informações, confira este problema do GitHub.

Logging

Habilite o Information ou um nível inferior de registro para diagnosticar problemas. O arquivo a seguir appsettings.json habilita o log de informações da API de Proteção de Dados:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.DataProtection": "Information"
    }
  },
  "AllowedHosts": "*"
}

Para mais informações sobre logging, consulte Logging em .NET e ASP.NET Core.

Recursos adicionais

Quando o sistema de Proteção de Dados é inicializado, ele aplica as configurações padrão com base no ambiente operacional. Essas configurações são apropriadas para aplicativos em execução em um único computador. No entanto, há casos em que um desenvolvedor pode querer alterar as configurações padrão:

  • O aplicativo é distribuído em vários computadores.
  • Por motivos de conformidade.

Para esses cenários, o sistema de Proteção de Dados oferece uma API de configuração avançada.

Warning

Semelhante aos arquivos de configuração, o anel de chave de proteção de dados deve ser protegido usando as permissões apropriadas. Você pode optar por criptografar chaves em repouso, mas isso não impede que os ciberataques criem novas chaves. Consequentemente a segurança do aplicativo é afetada. O local de armazenamento configurado com a Proteção de Dados deve ter seu acesso limitado ao próprio aplicativo, semelhante à maneira como você protegeria os arquivos de configuração. Por exemplo, se você optar por armazenar seu anel de chaves no disco, use permissões do sistema de arquivos. Certifique-se de que apenas a identidade sob a qual seu aplicativo web é executado tenha acesso de leitura, gravação e criação a esse diretório. Se você usar o Armazenamento de Blobs do Azure, somente o aplicativo Web deverá ter a capacidade de ler, gravar ou criar novas entradas no repositório de blobs.

O método de extensão AddDataProtection retorna um IDataProtectionBuilder, que expõe métodos de extensão que você pode encadear para configurar opções de Proteção de Dados.

Os seguintes pacotes NuGet são necessários para as extensões de Proteção de Dados usadas neste artigo:

Note

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Proteger chaves com o Azure Key Vault (ProtectKeysWithAzureKeyVault)

Para interagir com o Azure Key Vault localmente usando credenciais de desenvolvedor, entre em sua conta de armazenamento no Visual Studio ou entre com a CLI do Azure. Se você ainda não instalou a CLI do Azure, confira Como instalar a CLI do Azure. Você pode executar o seguinte comando no painel do PowerShell do Desenvolvedor no Visual Studio ou em um shell de comando ao não usar o Visual Studio:

az login

Para obter mais informações, consulte Entrar no Azure usando ferramentas de desenvolvedor.

Ao configurar o cofre de chaves no portal do Entra ou Azure:

  • Configure o cofre de chaves para usar o RABC (controle de acesso baseado em função) do Azure. Se você não estiver operando em uma Rede Virtual do Azure, inclusive para desenvolvimento local e teste, confirme se o acesso público na etapa rede está habilitado (verificado). A habilitação do acesso público só expõe o ponto de extremidade do cofre de chaves. Contas autenticadas ainda são necessárias para acesso.

  • Crie um Recurso Gerenciado do Azure Identity (ou adicione uma função ao Recurso Gerenciado Identity existente que você planeja usar) com a função de Usuário de Criptografia do Key Vault. Atribua o Identity Gerenciado ao Serviço de Aplicativo do Azure que está hospedando a implantação: Configurações>Identity>Atribuído pelo usuário>Adicionar.

    Note

    Se você também planeja executar um aplicativo localmente com um usuário autorizado para acesso a blobs usando a CLI do Azure ou a Autenticação do Serviço do Azure do Visual Studio, adicione sua conta de usuário do Azure para desenvolvedor no Controle de Acesso (IAM) com a função Usuário Cripto do Key Vault. Se você quiser usar a CLI do Azure por meio do Visual Studio, execute o az login comando no painel do PowerShell do Desenvolvedor e siga os prompts para autenticar com o locatário.

  • Quando a criptografia de chave estiver ativa, as chaves no arquivo de chave incluem o comentário "This key is encrypted with Azure Key Vault." Depois de iniciar o aplicativo, selecione o comando Exibir/editar no menu de contexto no final da linha de chave para confirmar se uma chave está presente com a segurança do cofre de chaves aplicada.

  • Você também pode habilitar o rodízio automático de chaves do cofre de chaves sem se preocupar em descriptografar cargas com chaves de proteção de dados com base em chaves expiradas/giradas do cofre de chaves. Cada chave de proteção de dados gerada inclui uma referência à chave do cofre de chaves usada para criptografá-la. Apenas certifique-se de manter as chaves expiradas no cofre de chaves, não as exclua. Além disso, use um identificador de chave sem versão na configuração do cofre de chaves do aplicativo, onde o GUID da chave não é adicionado ao final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection). Use um período de rotação semelhante para ambas as chaves com a chave do cofre de chaves girando com mais frequência do que a chave de proteção de dados para garantir que uma nova chave do cofre de chaves seja usada no momento da rotação da chave de proteção de dados.

Proteger chaves com o Azure Key Vault implementa um IXmlEncryptor que desabilita as configurações automáticas de proteção de dados, incluindo o local de armazenamento do anel de chaves. Para configurar o provedor de Armazenamento de Blobs do Azure para armazenar as chaves no armazenamento de blobs, siga as orientações em Provedores de armazenamento de chaves no ASP.NET Core e utilize uma das PersistKeysToAzureBlobStorage sobrecargas no aplicativo. O seguinte exemplo utiliza a sobrecarga que aceita um URI de blob e uma credencial de token (TokenCredential), contando com um Identity Gerenciado do Azure para controle de acesso baseado em função (RBAC).

Para configurar o provedor do Azure Key Vault, chame uma das sobrecargas ProtectKeysWithAzureKeyVault. O exemplo a seguir usa a sobrecarga que aceita o identificador de chave e a credencial de token (TokenCredential), contando com um Gerenciado Identity para RBAC em produção (ManagedIdentityCredential) ou um DefaultAzureCredential durante o desenvolvimento e teste. Outras sobrecargas aceitam um cliente de cofre de chaves ou um ID de cliente do aplicativo com segredo de cliente. Para obter mais informações, veja Principais provedores de armazenamento no ASP.NET Core.

Para obter mais informações sobre a API e a autenticação do SDK do Azure, consulte Autenticar aplicativos .NET nos serviços do Azure usando a biblioteca do Azure Identity e fornecer acesso a chaves, certificados e segredos do Key Vault com o controle de acesso baseado em função do Azure. Para obter orientações sobre logs, consulte Log com o SDK do Azure para .NET: log sem registro do cliente. Para aplicativos que usam injeção de dependência, um aplicativo pode chamar AddAzureClientsCore, passando true para enableLogForwarding, para criar e conectar a infraestrutura de log.

Para criar uma chave no portal do Azure, consulte Início Rápido: Definir e recuperar uma chave do Azure Key Vault usando o portal do Azure. Dê a chave, pelo menos Get, Unwrap Keye Wrap Key permissões. Registre o identificador de chave para uso com a configuração do aplicativo. Se você planeja habilitar a rotação automática da chave do cofre de chaves, registre o identificador de chave sem versão específica, onde não há um GUID de chave colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

No arquivo Program onde os serviços são registrados:

TokenCredential? credential;

if (builder.Environment.IsProduction())
{
    credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
    // Local development and testing only
    DefaultAzureCredentialOptions options = new()
    {
        // Specify the tenant ID to use the dev credentials when running the app locally
        // in Visual Studio.
        VisualStudioTenantId = "{TENANT ID}",
        SharedTokenCacheTenantId = "{TENANT ID}"
    };

    credential = new DefaultAzureCredential(options);
}

services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

{MANAGED IDENTITY CLIENT ID}: o ID do cliente gerenciado do Azure Identity (GUID).

{TENANT ID}: ID do locatário.

{APPLICATION NAME}: SetApplicationName define o nome exclusivo desse aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre implantações do aplicativo.

{BLOB URI}: URI completo para o arquivo de chave. O URI é gerado pelo Armazenamento do Azure quando você cria o arquivo de chave. Não use um SAS.

{KEY IDENTIFIER}: identificador de chave do Azure Key Vault usado para criptografia de chave. Uma política de acesso permite que o aplicativo acesse o cofre de chaves com Get, Unwrap Keye Wrap Key permissões. A versão da chave é obtida da chave no portal do Entra ou do Azure depois que ela é criada. Se você habilitar a rotação automática da chave do cofre de chaves, certifique-se de usar um identificador de chave sem versão na configuração do cofre de chaves do aplicativo, em que o GUID de chave não é colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

Para que um aplicativo se comunique e se autorize com o Azure Key Vault, o Azure.Identity pacote NuGet deve ser referenciado pelo aplicativo.

Note

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Note

Em ambientes que não são Production, o exemplo anterior usa o recurso DefaultAzureCredential para simplificar a autenticação ao desenvolver e implantar aplicativos no Azure, combinando credenciais usadas em ambientes de hospedagem do Azure com credenciais usadas no desenvolvimento local. Para obter mais informações, consulte Autenticar aplicativos .NET hospedados no Azure em recursos do Azure usando uma identidade gerenciada atribuída pelo sistema.

Se o aplicativo usar os pacotes mais antigos do Azure (Microsoft.AspNetCore.DataProtection.AzureStorage e Microsoft.AspNetCore.DataProtection.AzureKeyVault), recomendamos remover essas referências e atualizar para os pacotes Azure.Extensions.AspNetCore.DataProtection.Blobs e Azure.Extensions.AspNetCore.DataProtection.Keys. Os pacotes mais recentes abordam problemas principais de segurança e estabilidade.

Abordagem alternativa de SAS (assinatura de acesso compartilhado): como alternativa ao uso de um recurso gerenciado Identity para acessar o blob de chaves no Armazenamento de Blobs do Azure, você pode chamar a sobrecarga PersistKeysToAzureBlobStorage que aceita um URI de blob com um token SAS. O exemplo a seguir continua a usar um ManagedIdentityCredential (produção) ou DefaultAzureCredential (desenvolvimento e teste) para seu TokenCredential, como visto no exemplo anterior:

services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

{APPLICATION NAME}: SetApplicationName define o nome exclusivo desse aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre implantações do aplicativo.

{BLOB URI WITH SAS}: o URI completo em que o arquivo de chave deve ser armazenado com o token SAS como um parâmetro de cadeia de caracteres de consulta. O URI é gerado pelo Armazenamento do Azure quando você solicita uma SAS para o arquivo de chave carregado.

{KEY IDENTIFIER}: identificador de chave do Azure Key Vault usado para criptografia de chave. Uma política de acesso permite que o aplicativo acesse o cofre de chaves com Get, Unwrap Keye Wrap Key permissões. A versão da chave é obtida da chave no portal do Entra ou do Azure depois que ela é criada. Caso você habilite o rodízio automático da chave do cofre de chaves, certifique-se de usar um identificador de chave sem versão na configuração do cofre de chaves do aplicativo, onde nenhum GUID de chave é colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

Manter chaves para o sistema de arquivos (PersistKeysToFileSystem)

Para armazenar chaves em um compartilhamento UNC em vez de no local padrão %LOCALAPPDATA%, configure o sistema com PersistKeysToFileSystem:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
}

Warning

Se você alterar o local de persistência de chave, o sistema não criptografará mais automaticamente as chaves em repouso, pois ele não sabe se o DPAPI é um mecanismo de criptografia apropriado.

Manter chaves em um banco de dados (PersistKeysToDbContext)

Para armazenar chaves em um banco de dados usando EntityFramework, configure o sistema com o pacote Microsoft.AspNetCore.DataProtection.EntityFrameworkCore :

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToDbContext<DbContext>()
}

O código anterior armazena as chaves no banco de dados configurado. O contexto de banco de dados que está sendo usado deve implementar IDataProtectionKeyContext. IDataProtectionKeyContext expõe a propriedade DataProtectionKeys

public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }

Essa propriedade representa a tabela na qual as chaves são armazenadas. Crie a tabela manualmente ou com Migrações DbContext. Para obter mais informações, consulte DataProtectionKey.

API de configuração de chaves de proteção (ProtectKeysWith\*)

Você pode configurar o sistema para proteger chaves em repouso chamando qualquer uma das ProtectKeysWith\* APIs de configuração. Considere o exemplo abaixo, que armazena chaves em um compartilhamento UNC e criptografa essas chaves em repouso com um certificado X.509 específico:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
        .ProtectKeysWithCertificate(Configuration["Thumbprint"]);
}

Você pode fornecer um X509Certificate2 para ProtectKeysWithCertificate, como um certificado carregado de um arquivo:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
        .ProtectKeysWithCertificate(
            new X509Certificate2("certificate.pfx", Configuration["Thumbprint"]));
}

Para obter mais exemplos e discussão sobre os mecanismos internos de criptografia de chave, consulte a criptografia de chave em repouso no Windows e no Azure usando ASP.NET Core.

Desproteger chaves com qualquer certificado (UnprotectKeysWithAnyCertificate)

Você pode girar certificados e descriptografar chaves em repouso usando uma matriz de certificados X509Certificate2 com UnprotectKeysWithAnyCertificate:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
        .ProtectKeysWithCertificate(
            new X509Certificate2("certificate.pfx", Configuration["MyPasswordKey"));
        .UnprotectKeysWithAnyCertificate(
            new X509Certificate2("certificate_old_1.pfx", Configuration["MyPasswordKey_1"]),
            new X509Certificate2("certificate_old_2.pfx", Configuration["MyPasswordKey_2"]));
}

Definir o tempo de vida da chave padrão (SetDefaultKeyLifetime)

Para configurar o sistema para usar um tempo de vida de chave de 14 dias em vez dos 90 dias padrão, use SetDefaultKeyLifetime:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .SetDefaultKeyLifetime(TimeSpan.FromDays(14));
}

Definir o nome do aplicativo (SetApplicationName)

Por padrão, o sistema de Proteção de Dados isola os aplicativos uns dos outros com base em seus caminhos de raiz de conteúdo , mesmo que compartilhem o mesmo repositório de chaves físicas. Esse isolamento impede que os aplicativos compreendam os conteúdos protegidos uns dos outros.

Para compartilhar cargas protegidas entre aplicativos:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .SetApplicationName("{APPLICATION NAME}");
}

SetApplicationName define DataProtectionOptions.ApplicationDiscriminator internamente. Para obter mais informações sobre como o discriminador é usado, consulte as seguintes seções mais adiante nesse artigo:

Desabilitar a geração automática de chaves (DisableAutomaticKeyGeneration)

Você pode ter um cenário em que não deseja que um aplicativo role automaticamente as chaves (criar novas chaves) à medida que elas se aproximam da expiração. Um exemplo desse cenário pode ser aplicativos configurados em uma relação primária/secundária, em que apenas o aplicativo primário é responsável por questões de gerenciamento de chaves e os aplicativos secundários simplesmente têm uma exibição somente leitura do anel de chaves. Os aplicativos secundários podem ser configurados para tratar o anel de chave como somente leitura configurando o sistema com DisableAutomaticKeyGeneration:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .DisableAutomaticKeyGeneration();
}

Isolamento por aplicativo

Quando o sistema de Proteção de Dados é fornecido por um host ASP.NET Core, ele isola automaticamente os aplicativos uns dos outros, mesmo que esses aplicativos estejam em execução na mesma conta de processo de trabalho e estejam usando o mesmo material de chave mestra. Isso é semelhante ao modificador IsolateApps do elemento system.web <machineKey> .

O mecanismo de isolamento funciona considerando cada aplicativo no computador local como um locatário exclusivo, portanto, o root IDataProtector para qualquer aplicativo específico inclui automaticamente a ID do aplicativo como um discriminador (ApplicationDiscriminator). A ID exclusiva do aplicativo é o caminho físico do aplicativo:

  • Para aplicativos hospedados no IIS, a ID exclusiva é o caminho físico do IIS do aplicativo. Se um aplicativo for implantado em um ambiente de Web farm, esse valor será estável supondo que os ambientes do IIS sejam configurados da mesma forma em todos os computadores no Web farm.
  • Para aplicativos auto-hospedados em execução no Kestrel servidor, a ID exclusiva é o caminho físico para o aplicativo no disco.

O identificador exclusivo foi projetado para sobreviver às redefinições, tanto do aplicativo individual quanto do próprio computador.

Esse mecanismo de isolamento pressupõe que os aplicativos não são mal-intencionados. Um aplicativo mal-intencionado sempre pode afetar qualquer outro aplicativo em execução na mesma conta de processo de trabalho. Em um ambiente de hospedagem compartilhado em que os aplicativos são mutuamente não confiáveis, o provedor de hospedagem deve tomar medidas para garantir o isolamento no nível do sistema operacional entre aplicativos, incluindo a separação dos repositórios de chaves subjacentes dos aplicativos.

Se o sistema de Proteção de Dados não for fornecido por um host ASP.NET Core (por exemplo, se você instanciá-lo por meio do tipo concreto do DataProtectionProvider), o isolamento do aplicativo será desabilitado por padrão. Quando o isolamento do aplicativo é desabilitado, todos os aplicativos apoiados pelo mesmo material de chave podem compartilhar cargas, desde que forneçam as finalidades apropriadas. Para fornecer isolamento de aplicativo nesse ambiente, chame o método SetApplicationName no objeto de configuração e forneça um nome exclusivo para cada aplicativo.

Proteção de dados e isolamento de aplicativo

Considere os seguintes pontos para isolamento do aplicativo:

  • Quando vários aplicativos são apontados para o mesmo repositório de chaves, a intenção é que os aplicativos compartilhem o mesmo material de chave mestra. A Proteção de Dados é desenvolvida com a suposição de que todos os aplicativos que compartilham um anel de chaves podem acessar todos os itens nesse anel de chave. O identificador exclusivo do aplicativo é usado para isolar chaves específicas do aplicativo derivadas das chaves fornecidas pelo anel de chaves. Ele não espera que permissões de nível de item, como as fornecidas pelo Azure KeyVault, sejam usadas para impor isolamento extra. A tentativa de permissões no nível do item gera erros de aplicativo. Se você não quiser contar com o isolamento interno do aplicativo, os locais de repositório de chaves separados devem ser usados e não compartilhados entre aplicativos.

  • O aplicativo discriminatório (ApplicationDiscriminator) é usado para permitir que diferentes aplicativos compartilhem o mesmo material de chave mestra, mas para manter suas cargas criptográficas distintas umas das outras. Para que os aplicativos possam ler as cargas criptográficas uns dos outros, eles devem ter o mesmo discriminador de aplicativo, que pode ser definido chamando SetApplicationName.

  • Se um aplicativo estiver comprometido (por exemplo, por um ataque RCE), todo o material de chave mestra acessível a esse aplicativo também deverá ser considerado comprometido, independentemente de seu estado de proteção em repouso. Isso implica que, se dois aplicativos forem apontados para o mesmo repositório, mesmo que usem discriminadores de aplicativo diferentes, o comprometimento de um deles será funcionalmente equivalente ao comprometimento de ambos.

    Essa cláusula "funcionalmente equivalente a um comprometimento de ambos" é mantida mesmo que os dois aplicativos usem mecanismos diferentes para proteção de chave em repouso. Normalmente, essa não é uma configuração esperada. O mecanismo de proteção de dados em repouso destina-se a fornecer proteção caso um ciberatacante obtenha acesso de leitura ao repositório. Um invasor cibernético que obtém acesso de gravação ao repositório (talvez porque alcançou a permissão de execução de código em um aplicativo) pode inserir chaves mal-intencionadas no armazenamento. O sistema de proteção de dados intencionalmente não fornece proteção contra um invasor cibernético que obtém acesso de gravação ao repositório de chaves.

  • Se os aplicativos precisarem permanecer verdadeiramente isolados uns dos outros, eles deverão usar repositórios de chaves diferentes. Isso naturalmente sai da definição de "isolado". Os aplicativos não serão isolados se todos tiverem acesso de Leitura e Gravação aos armazenamentos de dados uns dos outros.

Como alterar algoritmos com UseCryptographicAlgorithms

A pilha de Proteção de Dados permite que você altere o algoritmo padrão usado pelas chaves recém-geradas. A maneira mais simples de fazer isso é chamar UseCryptographicAlgorithms do retorno de chamada de configuração:

services.AddDataProtection()
    .UseCryptographicAlgorithms(
        new AuthenticatedEncryptorConfiguration()
    {
        EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
        ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
    });

O EncryptionAlgorithm padrão é AES-256-CBC e o Padrão ValidationAlgorithm é HMACSHA256. A política padrão pode ser definida por um administrador do sistema por meio de uma política de todo o computador, mas uma chamada explícita para UseCryptographicAlgorithms substituir a política padrão.

Chamar UseCryptographicAlgorithms permite que você especifique o algoritmo desejado de uma lista interna predefinida. Você não precisa se preocupar com os detalhes de implementação do algoritmo. No cenário acima, o sistema de Proteção de Dados tenta usar a implementação de CNG do AES se estiver em execução no Windows. Caso contrário, ele voltará para a classe gerenciada System.Security.Cryptography.Aes .

Você pode especificar manualmente uma implementação por meio de uma chamada para UseCustomCryptographicAlgorithms.

Tip

A alteração de algoritmos não afeta as chaves existentes no anel de chave. Ela afeta apenas as chaves recém-geradas.

Especificando algoritmos gerenciados personalizados

Para especificar algoritmos gerenciados personalizados, crie uma instância ManagedAuthenticatedEncryptorConfiguration que aponte para os tipos de implementação:

serviceCollection.AddDataProtection()
    .UseCustomCryptographicAlgorithms(
        new ManagedAuthenticatedEncryptorConfiguration()
    {
        // A type that subclasses SymmetricAlgorithm
        EncryptionAlgorithmType = typeof(Aes),

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

        // A type that subclasses KeyedHashAlgorithm
        ValidationAlgorithmType = typeof(HMACSHA256)
    });

Geralmente, as propriedades *Type devem apontar para implementações concretas e instanciáveis (por meio de um ctor sem parâmetros público) de SymmetricAlgorithm e KeyedHashAlgorithm, embora o sistema especialmente case alguns valores, como typeof(Aes) para conveniência.

Note

O SymmetricAlgorithm deve ter um comprimento de chave de ≥ 128 bits e um tamanho de bloco de ≥ 64 bits e deve dar suporte à criptografia do modo CBC com preenchimento PKCS nº 7. O KeyedHashAlgorithm deve ter um tamanho de resumo de >= 128 bits e deve dar suporte a chaves de comprimento iguais ao comprimento de resumo do algoritmo de hash. O KeyedHashAlgorithm não é estritamente necessário para ser HMAC.

Especificando algoritmos CNG personalizados do Windows

Para especificar um algoritmo CNG personalizado do Windows usando a criptografia do modo CBC com validação HMAC, crie uma instância CngCbcAuthenticatedEncryptorConfiguration que contenha as informações algorítmicas:

services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(
        new CngCbcAuthenticatedEncryptorConfiguration()
    {
        // Passed to BCryptOpenAlgorithmProvider
        EncryptionAlgorithm = "AES",
        EncryptionAlgorithmProvider = null,

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

        // Passed to BCryptOpenAlgorithmProvider
        HashAlgorithm = "SHA256",
        HashAlgorithmProvider = null
    });

Note

O algoritmo de criptografia de bloco simétrico deve ter um comprimento de chave de >= 128 bits e um tamanho de bloco de >= 64 bits e deve dar suporte à criptografia do modo CBC com preenchimento PKCS nº 7. O algoritmo de hash deve ter um tamanho de resumo de >= 128 bits e deve dar suporte à abertura com o sinalizador BCRYPT_ALG_HANDLE_HMAC_FLAG. As propriedades *Provider podem ser definidas como nulas para usar o provedor padrão para o algoritmo especificado. Para obter mais informações, consulte a documentação BCryptOpenAlgorithmProvider.

Para especificar um algoritmo CNG personalizado do Windows usando a criptografia do modo Galois/Counter com validação, crie uma instância CngGcmAuthenticatedEncryptorConfiguration que contenha as informações algorítmicas:

services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(
        new CngGcmAuthenticatedEncryptorConfiguration()
    {
        // Passed to BCryptOpenAlgorithmProvider
        EncryptionAlgorithm = "AES",
        EncryptionAlgorithmProvider = null,

        // Specified in bits
        EncryptionAlgorithmKeySize = 256
    });

Note

O algoritmo de criptografia de bloco simétrico deve ter um comprimento de chave de >=128 bits, um tamanho de bloco de 128 bits e deve dar suporte à criptografia GCM. Você pode definir a propriedade EncryptionAlgorithmProvider como nula para usar o provedor padrão para o algoritmo especificado. Para obter mais informações, consulte a documentação BCryptOpenAlgorithmProvider.

Especificando outros algoritmos personalizados

Embora não seja exposto como uma API de primeira classe, o sistema de Proteção de Dados é extensível o suficiente para permitir a especificação de quase qualquer tipo de algoritmo. Por exemplo, é possível manter todas as chaves contidas em um HSM (Módulo de Segurança de Hardware) e fornecer uma implementação personalizada das principais rotinas de criptografia e descriptografia. Para obter mais informações, consulte IAuthenticatedEncryptor em Extensibilidade de criptografia principal.

Chaves persistentes ao hospedar em um contêiner do Docker

Ao hospedar em um contêiner do Docker, as chaves devem ser mantidas em:

Teclas persistentes com Redis

Somente as versões do Redis que dão suporte à Persistência de Dados Redis devem ser usadas para armazenar chaves. O Armazenamento de Blobs do Azure é persistente e pode ser usado para armazenar chaves. Para obter mais informações, confira este problema do GitHub.

Logging

Habilite o Information ou um nível inferior de registro para diagnosticar problemas. O arquivo a seguir appsettings.json habilita o log de informações da API de Proteção de Dados:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.DataProtection": "Information"
    }
  }
}

Para mais informações sobre logging, consulte Logging em .NET e ASP.NET Core.

Recursos adicionais