Nyckelhantering i ASP.NET Core

Dataskyddssystemet hanterar automatiskt livslängden för huvudnycklar som används för att skydda och ta bort skyddet av nyttolaster. Varje nyckel kan finnas i ett av fyra steg:

  • Skapad – nyckeln finns i nyckelringen men har ännu inte aktiverats. Nyckeln bör inte användas för nya Skydda-åtgärder förrän tillräckligt med tid har gått för att nyckeln har haft en chans att spridas till alla datorer som använder den här nyckelringen.

  • Aktiv – nyckeln finns i nyckelringen och bör användas för alla nya Skydda-åtgärder.

  • Utgått – nyckeln har nått sin naturliga livslängd och ska inte längre användas för nya skyddsåtgärder.

  • Återkallad – nyckeln komprometteras och får inte användas för nya Skydda-åtgärder.

Nycklar som skapats, är aktiva och har upphört att gälla kan alla användas för att ta bort skyddet av inkommande nyttolaster. Återkallade nycklar kan som standard inte användas för att ta bort skyddet av nyttolaster, men programutvecklaren kan åsidosätta det här beteendet om det behövs.

Varning

Utvecklaren kan frestas att ta bort en nyckel från nyckelringen (till exempel genom att ta bort motsvarande fil från filsystemet). Vid den tidpunkten är alla data som skyddas av nyckeln permanent oavkodningsbara, och det finns ingen nödlösning som det finns med återkallade nycklar. Att ta bort en nyckel är verkligen destruktivt beteende.

Standardinställning för nyckel

När dataskyddssystemet läser nyckelringen från lagringsplatsen försöker den hitta en "standardnyckel" från nyckelringen. Standardnyckeln används för nya Skydda-åtgärder.

Den allmänna heuristiken är att dataskyddssystemet väljer nyckeln med det senaste aktiveringsdatumet som standardnyckel. (Det finns en liten fudge-faktor för att tillåta snedställning av server-till-server-klockan.) Om nyckeln har upphört att gälla eller återkallats, och om programmet inte har inaktiverat automatisk nyckelgenerering, genereras en ny nyckel med omedelbar aktivering per nyckelns förfallodatum och löpande princip nedan.

Anledningen till att dataskyddssystemet genererar en ny nyckel omedelbart i stället för att återgå till en annan nyckel är att ny nyckelgenerering ska behandlas som en implicit förfallotid för alla nycklar som aktiverades före den nya nyckeln. Den allmänna tanken är att nya nycklar kan ha konfigurerats med olika algoritmer eller vilande krypteringsmekanismer än gamla nycklar, och systemet bör föredra den aktuella konfigurationen framför att falla tillbaka.

Det finns ett undantag. Om programutvecklaren har inaktiverat automatisk nyckelgenerering måste dataskyddssystemet välja något som standardnyckel. I det här återställningsscenariot väljer systemet den icke-återkallade nyckeln med det senaste aktiveringsdatumet, med prioritet för nycklar som har haft tid att spridas till andra datorer i klustret. Återställningssystemet kan till slut välja en standardnyckel som har upphört att gälla. Återställningssystemet väljer aldrig en återkallad nyckel som standardnyckel, och om nyckelringen är tom eller om varje nyckel har återkallats genereras ett fel vid initieringen.

Nyckel förfallodatum och nyckelrotation

När en nyckel skapas får den automatiskt ett aktiveringsdatum på { nu + 2 dagar } och ett förfallodatum på { nu + 90 dagar }. Tvådagarsfördröjningen före aktiveringen ger nyckeln tid att spridas genom systemet. Det innebär att andra program som pekar på lagringsplatsen kan observera nyckeln vid nästa period för automatisk uppdatering, vilket maximerar risken för att när nyckelringen blir aktiv har den spridits till alla program som kan behöva använda den.

Om standardnyckeln upphör att gälla inom 2 dagar och nyckelringen inte redan har en nyckel som är aktiv när standardnyckeln upphör att gälla, bevarar dataskyddssystemet automatiskt en ny nyckel till nyckelringen. Den nya nyckeln har aktiveringsdatumet { standardnyckelns förfallodatum } och ett förfallodatum på { nu + 90 dagar }. På så sätt kan systemet automatiskt rulla nycklar regelbundet utan avbrott i tjänsten.

Det kan finnas omständigheter där en nyckel skapas med omedelbar aktivering. Ett exempel är när programmet inte har körts på ett tag och alla nycklar i nyckelringen har upphört att gälla. När detta händer får nyckeln ett aktiveringsdatum på { nu } utan den normala aktiveringsfördröjningen på 2 dagar.

Standardnyckelns livslängd är 90 dagar, men detta kan konfigureras som i följande exempel.

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

En administratör kan också ändra standardsystemet i hela systemet, men ett explicit anrop till SetDefaultKeyLifetime åsidosätter alla systemomfattande principer. Standardnyckelns livslängd får inte vara kortare än 7 dagar.

Automatisk uppdatering av nyckelring

När dataskyddssystemet initieras läser det nyckelringen från den underliggande lagringsplatsen och cachelagrar den i minnet. Med den här cachen kan skydds- och avskyddsåtgärder fortsätta utan att behöva använda lagringsutrymmet. Systemet kontrollerar automatiskt lagringsplatsen för ändringar ungefär var 24:e timme eller när den aktuella standardnyckeln upphör att gälla, beroende på vilket som inträffar först.

Varning

Utvecklare bör mycket sällan (om någonsin) behöva använda nyckelhanterings-API:erna direkt. Dataskyddssystemet utför automatisk nyckelhantering enligt beskrivningen ovan.

Dataskyddssystemet exponerar ett gränssnitt IKeyManager som kan användas för att inspektera och göra ändringar i nyckelringen. DI-systemet som tillhandahöll instansen av IDataProtectionProvider kan också tillhandahålla en instans av IKeyManager för din förbrukning. Du kan också hämta IKeyManager direkt från IServiceProvider som i exemplet nedan.

Alla åtgärder som ändrar nyckelringen (som att uttryckligen skapa en ny nyckel eller utföra en återkallelse) kommer att ogiltigförklara cacheminnet. Nästa anrop till Protect eller Unprotect gör att dataskyddssystemet läser om nyckelringen och återskapar cachen.

Exemplet nedan visar hur du använder IKeyManager gränssnittet för att inspektera och manipulera nyckelringen, inklusive att återkalla befintliga nycklar och generera en ny nyckel manuellt.

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

Om du vill se kodkommentar översatta till andra språk än engelska kan du meddela oss i det här GitHub-diskussionsproblemet.

Nyckellagring

Dataskyddssystemet har en heuristisk metod där det försöker härleda en lämplig nyckellagringsplats och krypterings-at-rest-mekanism automatiskt. Den viktiga beständighetsmekanismen kan också konfigureras av apputvecklaren. I följande dokument beskrivs de inbyggda implementeringarna av dessa mekanismer: