Partilhar via


Configurar ASP.NET Proteção de Dados Principais

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

  • O aplicativo está espalhado por várias máquinas.
  • Por razões de conformidade.

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

Warning

Semelhante aos ficheiros de configuração, o anel de chaves de proteção de dados deve ser protegido usando permissões apropriadas. Você pode optar por criptografar chaves em repouso, mas isso não impede que os ciberatacantes criem novas chaves. Consequentemente, a segurança do seu 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 optar por armazenar o porta-chaves no disco, utilize as permissões do sistema de ficheiros. 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, escrever 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 podem ser encadeados para configurar as opções da Proteção de Dados.

Note

Este artigo foi escrito para um aplicativo executado em um contêiner do docker. Em um contêiner docker, o aplicativo sempre tem o mesmo caminho e, portanto, o mesmo discriminador de aplicativo. Os aplicativos que precisam ser executados em vários ambientes (por exemplo, locais e implantados) devem definir o discriminador de aplicativo 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, consulte Como instalar a CLI do Azure. Você pode executar o seguinte comando no painel Developer PowerShell no Visual Studio ou em um shell de comando quando não estiver usando o Visual Studio:

az login

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

Ao criar o Key Vault no portal Entra ou Azure:

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

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

    Note

    Se também pretender executar uma aplicação localmente com um utilizador autorizado para acesso a Blob usando o CLI do Azure ou a Autenticação de Serviço do Azure do Visual Studio, adicione a sua conta de utilizador de Azure de desenvolvedor no Controlo de Acesso (IAM) com a função Utilizador de Criptografia do Cofre de Chaves. Se você quiser usar a CLI do Azure por meio do Visual Studio, execute o az login comando no painel Developer PowerShell e siga os prompts para autenticar com o locatário.

  • Quando a criptografia de chave está 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 chaves para confirmar que uma chave está presente com a segurança do cofre de chaves aplicada.

  • Opcionalmente, pode ativar a rotação automática de chaves do cofre sem se preocupar em desencriptar cargas úteis com chaves de proteção de dados originadas de chaves de cofre expiradas ou rotativas. 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 do cofre de chaves; não as apague no cofre de chaves. Além disso, utilize um identificador de chave sem versão na configuração do cofre de chaves da aplicação, onde não é colocado nenhum GUID de chave no 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 girando mais frequentemente do que a chave de proteção de dados para garantir que uma nova chave do cofre seja utilizada durante a rotação da chave de proteção de dados.

A proteção de chaves com o Cofre de Chaves do Azure implementa um IXmlEncryptor que desativa as configurações automáticas de proteção de dados, incluindo o local de armazenamento das chaves. Para configurar o provedor de Armazenamento em Blob do Azure para armazenar as chaves no armazenamento em blob, siga as orientações de Provedores de armazenamento de chaves no ASP.NET Core e chame uma das PersistKeysToAzureBlobStorage sobrecargas na aplicação. O exemplo a seguir usa a sobrecarga que aceita um URI de blob e uma credencial de token (TokenCredential), confiando num sistema gerido pela Azure para controle de acesso baseado em função (RBAC).

Para configurar o fornecedor do Azure Key Vault, chame uma das ProtectKeysWithAzureKeyVault sobrecargas. O exemplo a seguir usa a sobrecarga que aceita identificador de chave e credencial de token (TokenCredential), confiando em um Managed 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 de aplicação com segredo de cliente. Para obter mais informações, consulte Provedores de armazenamento de chaves no ASP.NET Core.

Para obter mais informações sobre a API e a autenticação do SDK do Azure, consulte Autenticar aplicativos .NET para serviços do Azure usando a biblioteca do Azure Identity e Fornecer acesso a chaves, certificados e segredos do Cofre da Chave com o controle de acesso baseado em função do Azure. Para obter orientações de registo, consulte Registo com o SDK do Azure para .NET: Registo sem registo de cliente. Para aplicações que usam injeção de dependência, uma aplicação pode chamar AddAzureClientsCore, passando true para enableLogForwarding, para criar e conectar a infraestrutura de registro.

Para criar uma chave no portal do Azure, consulte Guia de início rápido: definir e recuperar uma chave do Cofre de Chaves do Azure 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 planeia habilitar a rotação automática da chave no cofre de chaves, registe o identificador de chave sem versão, que não tenha qualquer GUID de chave no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

No ficheiro onde os Program serviços estão registados:

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}: A ID do Cliente Gerenciado Identity do Azure (GUID).

{TENANT ID}: ID do inquilino.

{APPLICATION NAME}: SetApplicationName define o nome exclusivo deste aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre as 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 utilize uma SAS.

{KEY IDENTIFIER}: Identificador de chave do Azure Key Vault usado para criptografia de chave. Uma política de acesso permite que o aplicativo aceda o cofre de chaves com Get, Unwrap Key e permissões Wrap Key. A versão da chave é obtida a partir da chave no portal do Entra ou do Azure após a sua criação. Se ativares a rotação automática da chave do cofre das chaves, certifica-te de usar um identificador de chave sem versão na configuração do cofre das chaves da aplicação, onde nenhum GUID da chave é 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 orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos na seção Instalar e gerenciar pacotes em Workflow de utilização de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.

Note

Em ambientes que não são de produção, o exemplo anterior usa DefaultAzureCredential para simplificar a autenticação ao desenvolver aplicativos que implantam 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 ao sistema.

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

Abordagem alternativa de assinatura de acesso compartilhado (SAS): como alternativa ao uso de um Gerenciado Identity para acesso ao blob de chave no Armazenamento de Blobs do Azure, você pode chamar a PersistKeysToAzureBlobStorage sobrecarga 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 deste aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre as implantações do aplicativo.

{BLOB URI WITH SAS}: O URI completo onde 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 aceda o cofre de chaves com Get, Unwrap Key e permissões Wrap Key. A versão da chave é obtida a partir da chave no portal do Entra ou do Azure após a sua criação. Caso ative 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 da aplicação, onde nenhum GUID de chave é colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

Chaves persistentes 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 da chave, o sistema não criptografará mais automaticamente as chaves em repouso, pois não sabe se o DPAPI é um mecanismo de criptografia apropriado.

Persistir chaves num banco de dados (PersistKeysToDbContext)

Para armazenar chaves em um banco de dados usando o 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 do banco de dados em uso deve implementar IDataProtectionKeyContext. IDataProtectionKeyContext expõe a propriedade DataProtectionKeys

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

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

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

Você pode configurar o sistema para proteger as 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 a partir 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"]);

Pode fornecer um X509Certificate2 para ProtectKeysWithCertificate, como, por exemplo, um certificado carregado a partir de um ficheiro:

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ão sobre os mecanismos internos de criptografia de chave, consulte Criptografia de chave em repouso no Windows e no Azure usando o ASP.NET Core.

Desproteja chaves com qualquer certificado (UnprotectKeysWithAnyCertificate)

Você pode girar certificados e descriptografar chaves em repouso usando uma matriz de X509Certificate2 certificados 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 raiz de conteúdo , mesmo que eles compartilhem o mesmo repositório de chaves físicas. Esse isolamento impede que os aplicativos entendam as cargas protegidas uns dos outros.

Para partilhar cargas úteis protegidas entre aplicações:

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

SetApplicationName configura de forma interna DataProtectionOptions.ApplicationDiscriminator. Para fins de solução de problemas, o valor atribuído ao discriminador pelo framework pode ser registado com o seguinte código colocado após a construção de WebApplication em 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 neste artigo:

Warning

No .NET 6, o WebApplicationBuilder normaliza o caminho raiz do conteúdo para terminar com um DirectorySeparatorChar. Por exemplo, no Windows, o caminho raiz do conteúdo termina no \ Linux /. Outros hosts não normalizam o caminho. A maioria das aplicações que migram de HostBuilder ou WebHostBuilder não partilhará o mesmo nome de aplicação porque não terão o sufixo 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();

Desativar 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 teclas (crie novas chaves) à medida que elas se aproximam da expiração. Um exemplo deste cenário pode ser aplicações configuradas numa relação primária/secundária, onde apenas a aplicação primária é responsável pela gestão de chaves, e as aplicações secundárias têm apenas acesso de leitura ao porta-chaves. As aplicações secundárias podem ser configuradas para tratar o porta-chaves como somente leitura ao configurar o sistema com DisableAutomaticKeyGeneration:

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

Isolamento por aplicação

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 sendo executados na mesma conta de processo de trabalho e estejam usando o mesmo material de chaveamento mestre. Isso é semelhante ao modificador IsolateApps do elemento <machineKey> do System.Web.

O mecanismo de isolamento funciona considerando cada aplicação na máquina local como um locatário exclusivo, portanto, o IDataProtector enraizado em qualquer aplicação inclui automaticamente o identificador da aplicação como um discriminador (ApplicationDiscriminator). O ID exclusivo do aplicativo é o caminho físico do aplicativo:

  • Para aplicações alojadas no IIS, a ID exclusiva é o caminho físico da aplicação no IIS. Se um aplicativo for implantado em um ambiente de web farm, esse valor será estável supondo que os ambientes do IIS sejam configurados de forma semelhante em todas as máquinas da web farm.
  • Para aplicativos auto-hospedados em execução no servidor, a KestrelID exclusiva é o caminho físico para o aplicativo no disco.

O identificador exclusivo foi projetado para sobreviver a redefinições, tanto do aplicativo individual quanto da própria máquina.

Esse mecanismo de isolamento pressupõe que os aplicativos não sejam maliciosos. 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 compartilhada em que os aplicativos não são mutuamente 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 instanciado através do tipo concreto DataProtectionProvider), o isolamento da aplicação será desativado por padrão. Quando o isolamento de aplicativos é desativado, todos os aplicativos apoiados pelo mesmo material de chaveamento podem compartilhar cargas úteis, desde que forneçam as finalidades apropriadas. Para fornecer isolamento de aplicativo nesse ambiente, chame o SetApplicationName método no objeto de configuração e forneça um nome exclusivo para cada aplicativo.

Proteção de dados e isolamento de aplicativos

Considere os seguintes pontos para o 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 o pressuposto de que todas as aplicações que partilham um porta-chaves podem aceder a todos os itens desse porta-chaves. O identificador exclusivo do aplicativo é usado para isolar chaves específicas do aplicativo derivadas das chaves fornecidas pelo porta-chaves. Ele não espera que as 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 no aplicativo. Se você não quiser confiar no isolamento interno do aplicativo, locais de armazenamento de chaves separados devem ser usados e não compartilhados entre aplicativos.

  • O discriminador de aplicativos (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 uma aplicação for comprometida (por exemplo, por um ataque RCE), todo o material da chave mestra acessível a essa aplicação também deve ser considerado comprometido, independentemente do 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 aplicativos diferentes, um comprometimento de um é funcionalmente equivalente a um comprometimento de ambos.

    Esta cláusula "funcionalmente equivalente a um compromisso de ambos" mantém-se mesmo que as duas aplicações utilizem mecanismos diferentes para a proteção de chaves em repouso. Normalmente, essa não é uma configuração esperada. O mecanismo de proteção em repouso destina-se a fornecer proteção no caso de um ciberinvasor obter acesso de leitura ao repositório. Um ciberatacante que obtém acesso de gravação ao repositório (talvez porque tenha obtido permissão de execução de código em um aplicativo) pode inserir chaves maliciosas no armazenamento. O sistema de Proteção de Dados intencionalmente não fornece proteção contra um ciberatacante que obtém acesso de gravação ao repositório de chaves.

  • Se os aplicativos precisarem permanecer verdadeiramente isolados uns dos outros, eles devem usar repositórios de chaves diferentes. Isto está naturalmente fora da definição de "isolado". As aplicações não estarão isoladas se todas tiverem acesso de leitura e escrita aos armazenamentos de dados umas das outras.

Alterando algoritmos com UseCryptographicAlgorithms

O conjunto de Proteção de Dados permite alterar o algoritmo padrão usado por chaves recém-geradas. A maneira mais simples de fazer isso é chamar UseCryptographicAlgorithms a partir do callback 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 de sistema através de uma política de abrangência da máquina, mas uma chamada explícita para UseCryptographicAlgorithms substitui a política padrão.

A chamada UseCryptographicAlgorithms permite especificar o algoritmo desejado a partir de uma lista interna predefinida. Você não precisa se preocupar com a implementação do algoritmo. No cenário acima, o sistema de Proteção de Dados tenta usar a implementação CNG do AES se estiver rodando no Windows. Caso contrário, ele retornará à 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 porta-chaves. Afeta apenas chaves recém-geradas.

Especificando algoritmos gerenciados personalizados

Para especificar algoritmos gerenciados personalizados, crie uma ManagedAuthenticatedEncryptorConfiguration instância 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 (através de um ctor público sem parâmetros) de SymmetricAlgorithm e KeyedHashAlgorithm, embora o sistema faça exceções para 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 ≥ de 64 bits, e deve suportar criptografia de modo CBC com preenchimento PKCS #7. O KeyedHashAlgorithm deve ter um tamanho de resumo de >= 128 bits e deve suportar chaves de comprimento igual 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 criptografia de modo CBC com validação HMAC, crie uma CngCbcAuthenticatedEncryptorConfiguration instância 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 cifra de bloco simétrico deve ter um comprimento de chave de >= 128 bits, um tamanho de bloco de >= 64 bits e deve suportar criptografia de modo CBC com preenchimento PKCS #7. O algoritmo de hash deve ter um tamanho de resumo de >= 128 bits e ser aberto com suporte ao sinalizador BCRYPT_ALG_HANDLE_HMAC_FLAG. As propriedades *Provider podem ser definidas como null 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 Galois/Counter Mode com validação, crie uma CngGcmAuthenticatedEncryptorConfiguration instância 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 cifra de bloco simétrico deve ter um comprimento de chave de >= 128 bits, um tamanho de bloco de exatamente 128 bits e deve suportar criptografia GCM. Você pode definir a EncryptionAlgorithmProvider propriedade como null 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 (Hardware Security Module) e fornecer uma implementação personalizada das rotinas principais 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 alojar num contentor Docker, as chaves devem ser mantidas em:

Teclas persistentes com Redis

Somente as versões do Redis que suportam a persistência de dados do Redis devem ser usadas para armazenar chaves. O armazenamento de Blob do Azure é persistente e pode ser usado para armazenar chaves. Para obter mais informações, consulte este problema do GitHub.

Logging

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

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

Para obter mais informações sobre registo, consulte Registos no .NET e no ASP.NET Core.

Recursos adicionais

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

  • O aplicativo está espalhado por várias máquinas.
  • Por razões de conformidade.

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

Warning

Semelhante aos ficheiros de configuração, o anel de chaves de proteção de dados deve ser protegido usando permissões apropriadas. Você pode optar por criptografar chaves em repouso, mas isso não impede que os ciberatacantes criem novas chaves. Consequentemente, a segurança do seu 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 optar por armazenar o porta-chaves no disco, utilize as permissões do sistema de ficheiros. 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, escrever 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 pode-se encadear para configurar as 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 orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos na seção Instalar e gerenciar pacotes em Workflow de utilização de pacotes (documentação do NuGet). Confirme as versões corretas do 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, consulte Como instalar a CLI do Azure. Você pode executar o seguinte comando no painel Developer PowerShell no Visual Studio ou em um shell de comando quando não estiver usando o Visual Studio:

az login

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

Ao criar o Key Vault no portal Entra ou Azure:

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

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

    Note

    Se também pretender executar uma aplicação localmente com um utilizador autorizado para acesso a Blob usando o CLI do Azure ou a Autenticação de Serviço do Azure do Visual Studio, adicione a sua conta de utilizador de Azure de desenvolvedor no Controlo de Acesso (IAM) com a função Utilizador de Criptografia do Cofre de Chaves. Se você quiser usar a CLI do Azure por meio do Visual Studio, execute o az login comando no painel Developer PowerShell e siga os prompts para autenticar com o locatário.

  • Quando a criptografia de chave está 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 chaves para confirmar que uma chave está presente com a segurança do cofre de chaves aplicada.

  • Opcionalmente, pode ativar a rotação automática de chaves do cofre sem se preocupar em desencriptar cargas úteis com chaves de proteção de dados originadas de chaves de cofre expiradas ou rotativas. 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 do cofre de chaves; não as apague no cofre de chaves. Além disso, utilize um identificador de chave sem versão na configuração do cofre de chaves da aplicação, onde não é colocado nenhum GUID de chave no 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 girando mais frequentemente do que a chave de proteção de dados para garantir que uma nova chave do cofre seja utilizada durante a rotação da chave de proteção de dados.

A proteção de chaves com o Cofre de Chaves do Azure implementa um IXmlEncryptor que desativa as configurações automáticas de proteção de dados, incluindo o local de armazenamento das chaves. Para configurar o provedor de Armazenamento em Blob do Azure para armazenar as chaves no armazenamento em blob, siga as orientações de Provedores de armazenamento de chaves no ASP.NET Core e chame uma das PersistKeysToAzureBlobStorage sobrecargas na aplicação. O exemplo a seguir usa a sobrecarga que aceita um URI de blob e uma credencial de token (TokenCredential), confiando num sistema gerido pela Azure para controle de acesso baseado em função (RBAC).

Para configurar o fornecedor do Azure Key Vault, chame uma das ProtectKeysWithAzureKeyVault sobrecargas. O exemplo a seguir usa a sobrecarga que aceita identificador de chave e credencial de token (TokenCredential), confiando em um Managed 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 de aplicação com segredo de cliente. Para obter mais informações, consulte Provedores de armazenamento de chaves no ASP.NET Core.

Para obter mais informações sobre a API e a autenticação do SDK do Azure, consulte Autenticar aplicativos .NET para serviços do Azure usando a biblioteca do Azure Identity e Fornecer acesso a chaves, certificados e segredos do Cofre da Chave com o controle de acesso baseado em função do Azure. Para obter orientações de registo, consulte Registo com o SDK do Azure para .NET: Registo sem registo de cliente. Para aplicações que usam injeção de dependência, uma aplicação pode chamar AddAzureClientsCore, passando true para enableLogForwarding, para criar e conectar a infraestrutura de registro.

Para criar uma chave no portal do Azure, consulte Guia de início rápido: definir e recuperar uma chave do Cofre de Chaves do Azure 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 planeia habilitar a rotação automática da chave no cofre de chaves, registe o identificador de chave sem versão, que não tenha qualquer GUID de chave no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

No ficheiro onde os Program serviços estão registados:

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}: A ID do Cliente Gerenciado Identity do Azure (GUID).

{TENANT ID}: ID do inquilino.

{APPLICATION NAME}: SetApplicationName define o nome exclusivo deste aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre as 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 utilize uma SAS.

{KEY IDENTIFIER}: Identificador de chave do Azure Key Vault usado para criptografia de chave. Uma política de acesso permite que o aplicativo aceda o cofre de chaves com Get, Unwrap Key e permissões Wrap Key. A versão da chave é obtida a partir da chave no portal do Entra ou do Azure após a sua criação. Se ativares a rotação automática da chave do cofre das chaves, certifica-te de usar um identificador de chave sem versão na configuração do cofre das chaves da aplicação, onde nenhum GUID da chave é 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 orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos na seção Instalar e gerenciar pacotes em Workflow de utilização de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.

Note

Em ambientes que não são de produção, o exemplo anterior usa DefaultAzureCredential para simplificar a autenticação ao desenvolver aplicativos que implantam 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 ao sistema.

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

Abordagem alternativa de assinatura de acesso compartilhado (SAS): como alternativa ao uso de um Gerenciado Identity para acesso ao blob de chave no Armazenamento de Blobs do Azure, você pode chamar a PersistKeysToAzureBlobStorage sobrecarga 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 deste aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre as implantações do aplicativo.

{BLOB URI WITH SAS}: O URI completo onde 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 aceda o cofre de chaves com Get, Unwrap Key e permissões Wrap Key. A versão da chave é obtida a partir da chave no portal do Entra ou do Azure após a sua criação. Caso ative 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 da aplicação, onde nenhum GUID de chave é colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection).

Chaves persistentes 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 da chave, o sistema não criptografará mais automaticamente as chaves em repouso, pois não sabe se o DPAPI é um mecanismo de criptografia apropriado.

Persistir chaves num banco de dados (PersistKeysToDbContext)

Para armazenar chaves em um banco de dados usando o 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 do banco de dados em uso deve implementar IDataProtectionKeyContext. IDataProtectionKeyContext expõe a propriedade DataProtectionKeys

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

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

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

Você pode configurar o sistema para proteger as 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"]);
}

Pode fornecer um X509Certificate2 para ProtectKeysWithCertificate, como, por exemplo, um certificado carregado a partir de um ficheiro:

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ões sobre os mecanismos internos de criptografia de chave, consulte Criptografia de chave em repouso no Windows e no Azure usando o ASP.NET Core.

Desproteja chaves com qualquer certificado (UnprotectKeysWithAnyCertificate)

Você pode girar certificados e descriptografar chaves em repouso usando uma matriz de X509Certificate2 certificados 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 raiz de conteúdo , mesmo que eles compartilhem o mesmo repositório de chaves físicas. Esse isolamento impede que os aplicativos entendam as cargas protegidas uns dos outros.

Para partilhar cargas úteis protegidas entre aplicações:

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

SetApplicationName configura de forma interna DataProtectionOptions.ApplicationDiscriminator. Para obter mais informações sobre como o discriminador é usado, consulte as seguintes seções mais adiante neste artigo:

Desativar 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 teclas (crie novas chaves) à medida que elas se aproximam da expiração. Um exemplo deste cenário pode ser aplicações configuradas numa relação primária/secundária, onde apenas a aplicação primária é responsável pela gestão de chaves, e as aplicações secundárias têm apenas acesso de leitura ao porta-chaves. As aplicações secundárias podem ser configuradas para tratar o porta-chaves como somente leitura ao configurar o sistema com DisableAutomaticKeyGeneration:

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

Isolamento por aplicação

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 sendo executados na mesma conta de processo de trabalho e estejam usando o mesmo material de chaveamento mestre. Isso é semelhante ao modificador IsolateApps do elemento <machineKey> do System.Web.

O mecanismo de isolamento funciona considerando cada aplicação na máquina local como um locatário exclusivo, portanto, o IDataProtector enraizado em qualquer aplicação inclui automaticamente o identificador da aplicação como um discriminador (ApplicationDiscriminator). O ID exclusivo do aplicativo é o caminho físico do aplicativo:

  • Para aplicações alojadas no IIS, a ID exclusiva é o caminho físico da aplicação no IIS. Se um aplicativo for implantado em um ambiente de web farm, esse valor será estável supondo que os ambientes do IIS sejam configurados de forma semelhante em todas as máquinas da web farm.
  • Para aplicativos auto-hospedados em execução no servidor, a KestrelID exclusiva é o caminho físico para o aplicativo no disco.

O identificador exclusivo foi projetado para sobreviver a redefinições, tanto do aplicativo individual quanto da própria máquina.

Esse mecanismo de isolamento pressupõe que os aplicativos não sejam maliciosos. 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 compartilhada em que os aplicativos não são mutuamente 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 instanciado através do tipo concreto DataProtectionProvider), o isolamento da aplicação será desativado por padrão. Quando o isolamento de aplicativos é desativado, todos os aplicativos apoiados pelo mesmo material de chaveamento podem compartilhar cargas úteis, 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 aplicativos

Considere os seguintes pontos para o 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 o pressuposto de que todas as aplicações que partilham um porta-chaves podem aceder a todos os itens desse porta-chaves. O identificador exclusivo do aplicativo é usado para isolar chaves específicas do aplicativo derivadas das chaves fornecidas pelo porta-chaves. Ele não espera que as 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 no aplicativo. Se você não quiser confiar no isolamento interno do aplicativo, locais de armazenamento de chaves separados devem ser usados e não compartilhados entre aplicativos.

  • O discriminador de aplicativos (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 uma aplicação for comprometida (por exemplo, por um ataque RCE), todo o material da chave mestra acessível a essa aplicação também deve ser considerado comprometido, independentemente do 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 aplicativos diferentes, um comprometimento de um é funcionalmente equivalente a um comprometimento de ambos.

    Esta cláusula "funcionalmente equivalente a um compromisso de ambos" mantém-se mesmo que as duas aplicações utilizem mecanismos diferentes para a proteção de chaves em repouso. Normalmente, essa não é uma configuração esperada. O mecanismo de proteção em repouso destina-se a fornecer proteção no caso de um ciberinvasor obter acesso de leitura ao repositório. Um ciberatacante que obtém acesso de gravação ao repositório (talvez porque tenha obtido permissão de execução de código em um aplicativo) pode inserir chaves maliciosas no armazenamento. O sistema de Proteção de Dados intencionalmente não fornece proteção contra um ciberatacante que obtém acesso de gravação ao repositório de chaves.

  • Se os aplicativos precisarem permanecer verdadeiramente isolados uns dos outros, eles devem usar repositórios de chaves diferentes. Isto está naturalmente fora da definição de "isolado". As aplicações não estarão isoladas se todas tiverem acesso de leitura e escrita aos armazenamentos de dados umas das outras.

Alterando algoritmos com UseCryptographicAlgorithms

O conjunto de Proteção de Dados permite alterar o algoritmo padrão usado por chaves recém-geradas. A maneira mais simples de fazer isso é chamar UseCryptographicAlgorithms a partir do callback 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 de sistema através de uma política de abrangência da máquina, mas uma chamada explícita para UseCryptographicAlgorithms substitui a política padrão.

A chamada UseCryptographicAlgorithms permite especificar o algoritmo desejado a partir de uma lista interna predefinida. Você não precisa se preocupar com a implementação do algoritmo. No cenário acima, o sistema de Proteção de Dados tenta usar a implementação CNG do AES se estiver rodando no Windows. Caso contrário, ele retornará à 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 porta-chaves. Afeta apenas chaves recém-geradas.

Especificando algoritmos gerenciados personalizados

Para especificar algoritmos gerenciados personalizados, crie uma ManagedAuthenticatedEncryptorConfiguration instância 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 (através de um ctor público sem parâmetros) de SymmetricAlgorithm e KeyedHashAlgorithm, embora o sistema faça exceções para 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 ≥ de 64 bits, e deve suportar criptografia de modo CBC com preenchimento PKCS #7. O KeyedHashAlgorithm deve ter um tamanho de resumo de >= 128 bits e deve suportar chaves de comprimento igual 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 criptografia de modo CBC com validação HMAC, crie uma CngCbcAuthenticatedEncryptorConfiguration instância 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 cifra de bloco simétrico deve ter um comprimento de chave de >= 128 bits, um tamanho de bloco de >= 64 bits e deve suportar criptografia de modo CBC com preenchimento PKCS #7. O algoritmo de hash deve ter um tamanho de resumo de >= 128 bits e ser aberto com suporte ao sinalizador BCRYPT_ALG_HANDLE_HMAC_FLAG. As propriedades *Provider podem ser definidas como null 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 Galois/Counter Mode com validação, crie uma CngGcmAuthenticatedEncryptorConfiguration instância 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 cifra de bloco simétrico deve ter um comprimento de chave de >= 128 bits, um tamanho de bloco de exatamente 128 bits e deve suportar criptografia GCM. Você pode definir a EncryptionAlgorithmProvider propriedade como null 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 (Hardware Security Module) e fornecer uma implementação personalizada das rotinas principais 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 alojar num contentor Docker, as chaves devem ser mantidas em:

Teclas persistentes com Redis

Somente as versões do Redis que suportam a persistência de dados do Redis devem ser usadas para armazenar chaves. O armazenamento de Blob do Azure é persistente e pode ser usado para armazenar chaves. Para obter mais informações, consulte este problema do GitHub.

Logging

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

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

Para obter mais informações sobre registo, consulte Registos no .NET e no ASP.NET Core.

Recursos adicionais