Administración de claves en ASP.NET Core

El sistema de protección de datos administra automáticamente la duración de las claves maestras usadas para proteger y desproteger cargas. Cada clave puede existir en una de estas cuatro fases:

  • Creado: la clave existe en el anillo de claves, pero aún no se ha activado. La clave no debe usarse para las nuevas operaciones de protección hasta que haya transcurrido el tiempo suficiente para que la clave haya tenido la oportunidad de propagarse a todas las máquinas que consumen este anillo de clave.

  • Activo: la clave existe en el anillo de claves y debe usarse para todas las nuevas operaciones de protección.

  • Expirado: la clave ha ejecutado su duración natural y ya no debe usarse para las nuevas operaciones de protección.

  • Revocado: la clave está en peligro y no debe usarse para las nuevas operaciones de protección.

Las claves creadas, activas y expiradas se pueden usar para desproteger las cargas entrantes. Las claves revocadas de forma predeterminada no se pueden usar para desproteger cargas, pero el desarrollador de la aplicación puede invalidar este comportamiento si es necesario.

Advertencia

El desarrollador podría verse tentado a eliminar una clave del anillo de claves (por ejemplo, eliminando el archivo correspondiente del sistema de archivos). En ese momento, todos los datos protegidos por la clave no se pueden descifrar permanentemente y no hay ninguna invalidación de emergencia como la que hay con las claves revocadas. La eliminación de una clave es un comportamiento realmente destructivo y, por tanto, el sistema de protección de datos no expone ninguna API de primera clase para realizar esta operación.

Selección de clave predeterminada

Cuando el sistema de protección de datos lee el anillo de claves del repositorio de respaldo, intentará encontrar una clave "predeterminada" del anillo de claves. La clave predeterminada se usa para las nuevas operaciones de protección.

La heurística general es que el sistema de protección de datos elige la clave con la fecha de activación más reciente como clave predeterminada. (Hay un pequeño factor de potencia para permitir la asimetría del reloj de servidor a servidor). Si la clave ha expirado o revocado y la aplicación no ha deshabilitado la generación automática de claves, se generará una nueva clave con activación inmediata según la expiración de la clave y la directiva gradual siguiente.

La razón por la que el sistema de protección de datos genera una nueva clave inmediatamente en lugar de volver a otra clave es que la nueva generación de claves debe tratarse como una expiración implícita de todas las claves que se activaron antes de la nueva clave. La idea general es que las nuevas claves se hayan configurado con algoritmos diferentes o mecanismos de cifrado en reposo que las claves antiguas, y el sistema debe preferir la configuración actual antes que la retemor.

Hay una excepción. Si el desarrollador de aplicaciones ha deshabilitado la generación automática de claves,el sistema de protección de datos debe elegir algo como clave predeterminada. En este escenario de reserva, el sistema elegirá la clave no revocada con la fecha de activación más reciente, con preferencia dada a las claves que han tenido tiempo para propagarse a otras máquinas del clúster. Como resultado, el sistema de reserva puede terminar eligiendo una clave predeterminada expirada. El sistema de reserva nunca elegirá una clave revocada como clave predeterminada y, si el anillo de claves está vacío o se ha revocado cada clave, el sistema producirá un error al inicializarse.

Expiración y revolqueo de claves

Cuando se crea una clave, se le asigna automáticamente una fecha de activación de { ahora + 2 días } y una fecha de expiración de { ahora + 90 días }. El retraso de 2 días antes de la activación proporciona el tiempo clave para propagarse a través del sistema. Es decir, permite que otras aplicaciones que apuntan a la tienda de respaldo observen la clave en su siguiente período de actualización automática, lo que maximiza las posibilidades de que, cuando el anillo de claves se activa, se haya propagado a todas las aplicaciones que puedan necesitar usarla.

Si la clave predeterminada expirará en un plazo de 2 días y el anillo de claves aún no tiene una clave que estará activa tras la expiración de la clave predeterminada, el sistema de protección de datos conservará automáticamente una nueva clave en el anillo de claves. Esta nueva clave tiene una fecha de activación de { la fecha de expiración de la clave predeterminada } y una fecha de expiración de { ahora + 90 días }. Esto permite que el sistema revierte automáticamente las claves de forma periódica sin interrumpir el servicio.

Puede haber circunstancias en las que se creará una clave con activación inmediata. Un ejemplo sería cuando la aplicación no se ha ejecutado durante un tiempo y todas las claves del anillo de claves han expirado. Cuando esto sucede, a la clave se le da una fecha de activación de { now } sin el retraso normal de activación de 2 días.

La duración predeterminada de la clave es de 90 días, aunque se puede configurar como en el ejemplo siguiente.

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

Un administrador también puede cambiar el valor predeterminado en todo el sistema, aunque una llamada explícita a SetDefaultKeyLifetime invalidará cualquier directiva de todo el sistema. La duración de la clave predeterminada no puede ser inferior a 7 días.

Actualización automática del anillo de claves

Cuando se inicializa el sistema de protección de datos, lee el anillo de claves del repositorio subyacente y lo almacena en memoria caché. Esta memoria caché permite que las operaciones de protección y desprotección continúen sin tener que alcanzar el almacén de respaldo. El sistema comprobará automáticamente en el almacén de respaldo si hay cambios aproximadamente cada 24 horas o cuando expire la clave predeterminada actual, lo que sea primero.

Advertencia

Los desarrolladores rara vez (si alguna vez) necesitan usar las API de administración de claves directamente. El sistema de protección de datos realizará la administración automática de claves como se ha descrito anteriormente.

El sistema de protección de datos expone una interfaz IKeyManager que se puede usar para inspeccionar y realizar cambios en el anillo de claves. El sistema de DI que proporcionó la instancia de IDataProtectionProvider también puede proporcionar una instancia de para su IKeyManager consumo. Como alternativa, puede extraer la línea IKeyManager recta de como en el ejemplo IServiceProvider siguiente.

Cualquier operación que modifique el anillo de claves (crear una nueva clave explícitamente o realizar una revocación) invalidará la memoria caché en memoria. La siguiente llamada a o hará que el sistema de protección de Protect datos vuelva a leer el anillo de claves y vuelva a crear la memoria Unprotect caché.

En el ejemplo siguiente se muestra cómo usar la interfaz para inspeccionar y manipular el anillo de claves, incluida la revocación de las claves existentes y la generación manual de IKeyManager una nueva clave.

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
 */

Si quiere que los comentarios de código se traduzcan en más idiomas además del inglés, háganoslo saber en este problema de debate de GitHub.

Almacenamiento de claves

El sistema de protección de datos tiene una heurística por la que intenta deducir automáticamente una ubicación de almacenamiento de claves adecuada y un mecanismo de cifrado en reposo. El desarrollador de la aplicación también puede configurar el mecanismo de persistencia clave. En los documentos siguientes se de abordan las implementaciones de estos mecanismos: