Compartilhar via


Gerenciamento de chaves no ASP.NET Core

O sistema de proteção de dados gerencia automaticamente o tempo de vida de chaves mestras usadas para proteger e desproteger cargas. Cada chave pode existir em um dos quatro estágios:

  • Criada: a chave existe no anel de chaves, mas ainda não foi ativada. A chave não deve ser usada para novas operações de Proteção até que haja tempo suficiente para que a chave tenha tido a chance de se propagar para todos os computadores que utilizam este chaveiro.

  • Ativo: a chave existe no porta-chaves e deve ser usada para todas as novas operações de proteção.

  • Expirada: a chave atingiu seu tempo de vida natural e não deve mais ser usada para novas operações de proteção.

  • Revogada: a chave está comprometida e não deve ser usada para novas operações de Proteção.

As chaves criadas, ativas e expiradas podem ser usadas para desproteger as cargas de entrada. As chaves revogadas por padrão podem não ser usadas para desproteger cargas, mas o desenvolvedor do aplicativo pode substituir esse comportamento, se necessário.

Aviso

O desenvolvedor pode ficar tentado a deletar uma chave do chaveiro (por exemplo, removendo o arquivo correspondente do sistema de arquivos). Nesse ponto, todos os dados protegidos pela chave são permanentemente indecifráveis e não há substituição de emergência como há com chaves revogadas. Excluir uma chave é um comportamento verdadeiramente destrutivo.

Seleção de chave padrão

Quando o sistema de proteção de dados ler o conjunto de chaves do repositório de backup, ele tentará localizar uma chave "padrão" do conjunto de chaves. A chave padrão é usada para novas operações de Proteção.

A heurística geral é que o sistema de proteção de dados escolhe a chave com a data de ativação mais recente como a chave padrão. (Há um pequeno margem de ajuste para permitir o desvio de horário entre servidores.) Se a chave tiver expirado ou sido revogada e se o aplicativo não tiver desabilitado a geração automática de chaves, uma nova chave será gerada com ativação imediata de acordo com a política de expiração e renovação contínua da chave abaixo.

O motivo pelo qual o sistema de proteção de dados gera uma nova chave imediatamente em vez de voltar para uma chave diferente é que a nova geração de chave deve ser tratada como uma expiração implícita de todas as chaves que foram ativadas antes da nova chave. A ideia geral é que novas chaves podem ter sido configuradas com algoritmos diferentes ou mecanismos de criptografia em repouso do que chaves antigas, e o sistema deve preferir a configuração atual em vez de recuar.

Há uma exceção. Se o desenvolvedor de aplicativos tiver desabilitado a geração automática de chaves, o sistema de proteção de dados deverá escolher algo como a chave padrão. Nesse cenário de fallback, o sistema escolherá a chave não revogada com a data de ativação mais recente, com preferência dada às chaves que tiveram tempo de propagar para outros computadores no cluster. O sistema de fallback pode acabar escolhendo uma chave padrão expirada como resultado. O sistema de fallback nunca escolherá uma chave revogada como a chave padrão e, se o chaveiro estiver vazio ou cada chave tiver sido revogada, o sistema produzirá um erro após a inicialização.

Expiração e rolagem da chave

Quando uma chave é criada, ela recebe automaticamente uma data de ativação de { agora + 2 dias } e uma data de validade de { agora + 90 dias }. O atraso de dois dias antes da ativação dá tempo à chave para se propagar pelo sistema. Ou seja, isso permite que outros aplicativos que apontam para o repositório de backup observem a chave no próximo período de atualização automática, maximizando assim as chances de que, quando o chaveiro se tornar ativo, ele tenha se propagado para todos os aplicativos que possam precisar usá-la.

Se a chave padrão expirar dentro de dois dias e se o chaveiro ainda não tiver uma chave que estará ativa após a expiração da chave padrão, o sistema de proteção de dados persistirá automaticamente uma nova chave no chaveiro. Essa nova chave tem uma data de ativação de { data de validade da chave padrão } e uma data de validade de { agora + 90 dias }. Isso permite que o sistema troque automaticamente as chaves regularmente sem interrupção do serviço.

Pode haver circunstâncias em que uma chave será criada com ativação imediata. Um exemplo seria quando o aplicativo não for executado por um tempo e todas as chaves no chaveiro expirarem. Quando isso acontece, a chave recebe uma data de ativação de { now } sem o atraso normal de ativação de dois dias.

O tempo de vida da chave padrão é de 90 dias, embora isso seja configurável como no exemplo a seguir.

services.AddDataProtection()
       // use 14-day lifetime instead of 90-day lifetime
       .SetDefaultKeyLifetime(TimeSpan.FromDays(14));

Um administrador também pode alterar o padrão em todo o sistema, embora uma chamada explícita para SetDefaultKeyLifetime substitua qualquer política em todo o sistema. O tempo de vida da chave padrão não pode ser menor que sete dias.

Atualização automática do chaveiro digital

Quando o sistema de proteção de dados é inicializado, ele lê a chave criptográfica do repositório subjacente e a armazena na memória cache. Esse cache permite que as operações Proteger e Desproteger prossiga sem atingir o repositório de backup. O sistema verificará automaticamente o repositório de backup para alterações aproximadamente a cada 24 horas ou quando a chave padrão atual expirar, o que ocorrer primeiro.

Aviso

Os desenvolvedores devem usar diretamente as APIs de gerenciamento de chaves muito raramente, se é que devem usá-las. O sistema de proteção de dados executará o gerenciamento automático de chaves, conforme descrito acima.

O sistema de proteção de dados expõe uma interface IKeyManager que pode ser usada para inspecionar e alterar o conjunto de chaves. O sistema de DI que forneceu a instância do IDataProtectionProvider também pode fornecer uma instância do IKeyManager para seu consumo. Como alternativa, você pode realizar o pull do IKeyManager diretamente do IServiceProvider, como no exemplo abaixo.

Qualquer operação que modifique o anel de chaves (criando uma nova chave explicitamente ou executando uma revogação) invalidará o cache na memória. A próxima chamada para Protect ou Unprotect fará com que o sistema de proteção de dados releia o anel de chaves e reinicie o cache.

O exemplo a seguir demonstra como usar a interface IKeyManager para inspecionar e manipular o anel de chaves, incluindo revogar chaves existentes e gerar uma nova chave manualmente.

using System;
using System.IO;
using System.Threading;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.DependencyInjection;

public class Program
{
    public static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddDataProtection()
            // point at a specific folder and use DPAPI to encrypt keys
            .PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
            .ProtectKeysWithDpapi();
        var services = serviceCollection.BuildServiceProvider();

        // perform a protect operation to force the system to put at least
        // one key in the key ring
        services.GetDataProtector("Sample.KeyManager.v1").Protect("payload");
        Console.WriteLine("Performed a protect operation.");
        Thread.Sleep(2000);

        // get a reference to the key manager
        var keyManager = services.GetService<IKeyManager>();

        // list all keys in the key ring
        var allKeys = keyManager.GetAllKeys();
        Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
        foreach (var key in allKeys)
        {
            Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}");
        }

        // revoke all keys in the key ring
        keyManager.RevokeAllKeys(DateTimeOffset.Now, reason: "Revocation reason here.");
        Console.WriteLine("Revoked all existing keys.");

        // add a new key to the key ring with immediate activation and a 1-month expiration
        keyManager.CreateNewKey(
            activationDate: DateTimeOffset.Now,
            expirationDate: DateTimeOffset.Now.AddMonths(1));
        Console.WriteLine("Added a new key.");

        // list all keys in the key ring
        allKeys = keyManager.GetAllKeys();
        Console.WriteLine($"The key ring contains {allKeys.Count} key(s).");
        foreach (var key in allKeys)
        {
            Console.WriteLine($"Key {key.KeyId:B}: Created = {key.CreationDate:u}, IsRevoked = {key.IsRevoked}");
        }
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Performed a protect operation.
 * The key ring contains 1 key(s).
 * Key {1b948618-be1f-440b-b204-64ff5a152552}: Created = 2015-03-18 22:20:49Z, IsRevoked = False
 * Revoked all existing keys.
 * Added a new key.
 * The key ring contains 2 key(s).
 * Key {1b948618-be1f-440b-b204-64ff5a152552}: Created = 2015-03-18 22:20:49Z, IsRevoked = True
 * Key {2266fc40-e2fb-48c6-8ce2-5fde6b1493f7}: Created = 2015-03-18 22:20:51Z, IsRevoked = False
 */

Armazenamento de chave

O sistema de proteção de dados tem uma heurística pela qual tenta deduzir automaticamente um local de armazenamento de chaves apropriado e um mecanismo de criptografia em repouso. O mecanismo de persistência de chave também é configurável pelo desenvolvedor do aplicativo. Os documentos a seguir discutem as implementações internas desses mecanismos: