Zarządzanie kluczami w programie ASP.NET Core

System ochrony danych automatycznie zarządza okresem istnienia kluczy głównych używanych do ochrony i wyłączania ochrony ładunków. Każdy klucz może istnieć w jednym z czterech etapów:

  • Utworzono — klucz istnieje w pierścieniu kluczy, ale nie został jeszcze aktywowany. Klucz nie powinien być używany do nowych operacji ochrony, dopóki nie upłynął wystarczający czas, zanim klucz miał szansę na propagację do wszystkich maszyn, które zużywają ten pierścień kluczy.

  • Aktywny — klucz istnieje w pierścieniu kluczy i powinien być używany dla wszystkich nowych operacji Ochrony.

  • Wygasł — klucz ma swój naturalny okres istnienia i nie powinien być już używany do nowych operacji ochrony.

  • Odwołano — klucz jest naruszony i nie może być używany w przypadku nowych operacji ochrony.

Utworzone, aktywne i wygasłe klucze mogą być używane do wyrejecenia ładunków przychodzących. Odwołane klucze domyślnie nie mogą być używane do odłączania ładunków, ale deweloper aplikacji może w razie potrzeby zastąpić to zachowanie .

Ostrzeżenie

Deweloper może być kuszony, aby usunąć klucz z pierścienia kluczy (np. przez usunięcie odpowiedniego pliku z systemu plików). W tym momencie wszystkie dane chronione przez klucz są trwale niezdefiniowalne i nie ma przesłonięcia awaryjnego, takiego jak w przypadku odwołanych kluczy. Usunięcie klucza jest naprawdę destrukcyjnym zachowaniem, a w związku z tym system ochrony danych nie uwidacznia interfejsu API pierwszej klasy do wykonania tej operacji.

Wybór klucza domyślnego

Gdy system ochrony danych odczytuje pierścień kluczy z repozytorium kopii zapasowej, podejmie próbę zlokalizowania "domyślnego" klucza z pierścienia kluczy. Klucz domyślny jest używany w przypadku nowych operacji ochrony.

Ogólna heurystyka polega na tym, że system ochrony danych wybiera klucz z najnowszą datą aktywacji jako kluczem domyślnym. (Istnieje mały współczynnik rozmycia, aby umożliwić niesymetryczność zegara serwer-serwer). Jeśli klucz wygasł lub odwołany, a aplikacja nie wyłączyła automatycznego generowania kluczy, zostanie wygenerowany nowy klucz z natychmiastową aktywacją zgodnie z poniższymi zasadami wygasania i rolowania klucza.

Powodem, dla którego system ochrony danych generuje nowy klucz natychmiast, zamiast wracać do innego klucza, jest to, że nowa generacja kluczy powinna być traktowana jako niejawne wygaśnięcie wszystkich kluczy, które zostały aktywowane przed nowym kluczem. Ogólnie chodzi o to, że nowe klucze mogły zostać skonfigurowane przy użyciu różnych algorytmów lub mechanizmów szyfrowania w spoczynku niż stare klucze, a system powinien preferować bieżącą konfigurację powrotu.

Istnieje wyjątek. Jeśli deweloper aplikacji wyłączył automatyczne generowanie kluczy, system ochrony danych musi wybrać coś jako klucz domyślny. W tym scenariuszu rezerwowym system wybierze nieodwołany klucz z najnowszą datą aktywacji, z preferencjami podanymi kluczom, które miały czas na propagację do innych maszyn w klastrze. W rezultacie system rezerwowy może wybrać wygasły klucz domyślny. System rezerwowy nigdy nie wybierze odwołanego klucza jako klucza domyślnego, a jeśli pierścień kluczy jest pusty lub każdy klucz został odwołany, system wygeneruje błąd podczas inicjowania.

Wygaśnięcie i stopniowe klucza

Po utworzeniu klucza automatycznie otrzymuje on datę aktywacji { teraz + 2 dni } i datę wygaśnięcia { teraz + 90 dni }. 2-dniowe opóźnienie przed aktywacją daje kluczowy czas propagacji przez system. Oznacza to, że pozwala innym aplikacjom wskazującym magazyn zapasowy obserwować klucz w następnym okresie automatycznego odświeżania, co pozwala zmaksymalizować prawdopodobieństwo, że gdy pierścień kluczy stanie się aktywny, propaguje go do wszystkich aplikacji, które mogą wymagać jej użycia.

Jeśli klucz domyślny wygaśnie w ciągu 2 dni i jeśli pierścień kluczy nie ma jeszcze klucza, który będzie aktywny po wygaśnięciu klucza domyślnego, system ochrony danych automatycznie utrwał nowy klucz do pierścienia kluczy. Ten nowy klucz ma datę aktywacji { domyślną datę wygaśnięcia klucza } i datę wygaśnięcia { teraz + 90 dni }. Pozwala to systemowi na regularne wprowadzanie kluczy bez przerw w działaniu usługi.

W sytuacjach, w których klucz zostanie utworzony z natychmiastową aktywacją. Przykładem może być to, że aplikacja nie została uruchomiona przez pewien czas, a wszystkie klucze w pierścieniu kluczy wygasły. W takim przypadku klucz otrzymuje datę aktywacji { now } bez normalnego 2-dniowego opóźnienia aktywacji.

Domyślny okres istnienia klucza to 90 dni, chociaż można to skonfigurować tak, jak w poniższym przykładzie.

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

Administrator może również zmienić domyślny zakres systemu, chociaż jawne wywołanie SetDefaultKeyLifetime polecenia spowoduje zastąpienie wszystkich zasad dla całego systemu. Domyślny okres istnienia klucza nie może być krótszy niż 7 dni.

Automatyczne odświeżanie pierścienia kluczy

Gdy system ochrony danych inicjuje, odczytuje pierścień kluczy z bazowego repozytorium i buforuje go w pamięci. Ta pamięć podręczna umożliwia kontynuowanie operacji Ochrona i cofanie ochrony bez trafienia do magazynu kopii zapasowych. System automatycznie sprawdzi magazyn kopii zapasowych pod kątem zmian co około 24 godziny lub gdy bieżący klucz domyślny wygaśnie, w zależności od tego, co nastąpi wcześniej.

Ostrzeżenie

Deweloperzy powinni bardzo rzadko (jeśli kiedykolwiek) bezpośrednio korzystać z interfejsów API zarządzania kluczami. System ochrony danych będzie wykonywać automatyczne zarządzanie kluczami zgodnie z powyższym opisem.

System ochrony danych uwidacznia interfejs IKeyManager , który może służyć do sprawdzania i wprowadzania zmian w pierścieniu kluczy. System di, który dostarczył wystąpienie IDataProtectionProvider programu , może również zapewnić wystąpienie IKeyManager do użycia. Alternatywnie możesz ściągnąć IKeyManager prosto z tabeli IServiceProvider , jak w poniższym przykładzie.

Każda operacja, która modyfikuje pierścień kluczy (utworzenie nowego klucza jawnie lub wykonanie odwołania), spowoduje unieważnienie pamięci podręcznej w pamięci. Następne wywołanie metody Protect lub Unprotect spowoduje ponowne odczytanie pierścienia kluczy przez system ochrony danych i ponowne utworzenie pamięci podręcznej.

W poniższym przykładzie pokazano, jak używać interfejsu IKeyManager do inspekcji i manipulowania pierścieniem kluczy, w tym odwołując istniejące klucze i generując nowy klucz ręcznie.

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

Jeśli chcesz zobaczyć komentarze kodu przetłumaczone na języki inne niż angielski, poinformuj nas o tym w tym problemie z dyskusją w usłudze GitHub.

Magazyn kluczy

System ochrony danych ma algorytm heurystyczny, w którym próbuje automatycznie deduować odpowiednią lokalizację magazynu kluczy i mechanizm szyfrowania w spoczynku. Kluczowy mechanizm trwałości można również skonfigurować przez dewelopera aplikacji. W poniższych dokumentach omówiono wbudowane implementacje tych mechanizmów: