Rozszerzalność zarządzania kluczami w programie ASP.NET Core
Zapoznaj się z sekcją zarządzania kluczami przed przeczytaniem tej sekcji, ponieważ objaśniono niektóre podstawowe pojęcia dotyczące tych interfejsów API.
Ostrzeżenie: Typy implementujące dowolny z następujących interfejsów powinny być bezpieczne wątkowo dla wielu wywołujących.
Klucz
Interfejs IKey
jest podstawową reprezentacją klucza w systemie kryptograficznym. Termin klucz jest używany tutaj w sensie abstrakcyjnym, a nie w sensie literału "materiału klucza kryptograficznego". Klucz ma następujące właściwości:
Daty aktywacji, tworzenia i wygaśnięcia
Stan odwołania
Identyfikator klucza (identyfikator GUID)
Ponadto uwidacznia metodęCreateEncryptor
, IKey
która może służyć do tworzenia wystąpienia IAuthenticatedEncryptor powiązanego z tym kluczem.
Ponadto uwidacznia metodęCreateEncryptorInstance
, IKey
która może służyć do tworzenia wystąpienia IAuthenticatedEncryptor powiązanego z tym kluczem.
Uwaga
Nie ma interfejsu API do pobierania nieprzetworzonego IKey
materiału kryptograficznego z wystąpienia.
IKeyManager
Interfejs IKeyManager
reprezentuje obiekt odpowiedzialny za ogólny magazyn kluczy, pobieranie i manipulowanie. Uwidacznia trzy operacje wysokiego poziomu:
Utwórz nowy klucz i utrwali go w magazynie.
Pobierz wszystkie klucze z magazynu.
Odwoływanie co najmniej jednego klucza i utrwalanie informacji odwołania do magazynu.
Ostrzeżenie
Pisanie elementu IKeyManager
to bardzo zaawansowane zadanie, a większość deweloperów nie powinna jej próbować. Zamiast tego większość deweloperów powinna korzystać z obiektów oferowanych przez klasę XmlKeyManager .
XmlKeyManager
Typ to wbudowana XmlKeyManager
konkretna implementacja IKeyManager
. Zapewnia kilka przydatnych funkcji, w tym deponowanie kluczy i szyfrowanie kluczy w lokalizacji rest. Klucze w tym systemie są reprezentowane jako elementy XML (w szczególności XElement).
XmlKeyManager
zależy od kilku innych składników w trakcie wykonywania zadań:
AlgorithmConfiguration
, który określa algorytmy używane przez nowe klucze.IXmlRepository
, który kontroluje, gdzie klucze są utrwalane w magazynie.IXmlEncryptor
[opcjonalnie], który umożliwia szyfrowanie kluczy w lokalizacji rest.IKeyEscrowSink
[opcjonalnie], który zapewnia usługi deponowania kluczy.
IXmlRepository
, który kontroluje, gdzie klucze są utrwalane w magazynie.IXmlEncryptor
[opcjonalnie], który umożliwia szyfrowanie kluczy w lokalizacji rest.IKeyEscrowSink
[opcjonalnie], który zapewnia usługi deponowania kluczy.
Poniżej przedstawiono diagramy wysokiego poziomu, które wskazują, w jaki sposób te składniki są połączone w obrębie programu XmlKeyManager
.
Tworzenie klucza / TworzenieNowy klucz
W implementacji składnika jest używany do tworzenia unikatowego CreateNewKey
AlgorithmConfiguration
IAuthenticatedEncryptorDescriptor
elementu , który jest następnie serializowany jako XML. Jeśli istnieje ujście depozytu klucza, nieprzetworzony (niezaszyfrowany) kod XML jest dostarczany do ujścia na potrzeby długoterminowego przechowywania. Niezaszyfrowany kod XML jest następnie uruchamiany za pośrednictwem IXmlEncryptor
(jeśli jest to wymagane) w celu wygenerowania zaszyfrowanego dokumentu XML. Ten zaszyfrowany dokument jest utrwalany w długoterminowym magazynie za pośrednictwem elementu IXmlRepository
. (Jeśli nie IXmlEncryptor
jest skonfigurowany, niezaszyfrowany dokument jest utrwalany w pliku IXmlRepository
.)
Tworzenie klucza / TworzenieNowy klucz
W implementacji składnika jest używany do tworzenia unikatowego CreateNewKey
IAuthenticatedEncryptorConfiguration
IAuthenticatedEncryptorDescriptor
elementu , który jest następnie serializowany jako XML. Jeśli istnieje ujście depozytu klucza, nieprzetworzony (niezaszyfrowany) kod XML jest dostarczany do ujścia na potrzeby długoterminowego przechowywania. Niezaszyfrowany kod XML jest następnie uruchamiany za pośrednictwem IXmlEncryptor
(jeśli jest to wymagane) w celu wygenerowania zaszyfrowanego dokumentu XML. Ten zaszyfrowany dokument jest utrwalany w długoterminowym magazynie za pośrednictwem elementu IXmlRepository
. (Jeśli nie IXmlEncryptor
jest skonfigurowany, niezaszyfrowany dokument jest utrwalany w pliku IXmlRepository
.)
Pobieranie klucza /GetAllKeys
W implementacji GetAllKeys
pliku dokumenty XML reprezentujące klucze i odwołania są odczytywane z bazowego IXmlRepository
elementu . Jeśli te dokumenty są szyfrowane, system automatycznie je odszyfruje. XmlKeyManager
tworzy odpowiednie IAuthenticatedEncryptorDescriptorDeserializer
wystąpienia w celu deserializacji dokumentów z powrotem do IAuthenticatedEncryptorDescriptor
wystąpień, które następnie są opakowane w poszczególne IKey
wystąpienia. Ta kolekcja wystąpień IKey
jest zwracana do obiektu wywołującego.
Więcej informacji na temat konkretnych elementów XML można znaleźć w dokumencie w formacie magazynu kluczy.
IXmlRepository
Interfejs IXmlRepository
reprezentuje typ, który może utrwalać kod XML i pobierać kod XML z magazynu kopii zapasowych. Uwidacznia dwa interfejsy API:
GetAllElements
:IReadOnlyCollection<XElement>
StoreElement(XElement element, string friendlyName)
Implementacje IXmlRepository
nie muszą analizować kodu XML przechodzącego przez nie. Powinny traktować dokumenty XML jako nieprzezroczyste i pozwolić wyższym warstwom martwić się o generowanie i analizowanie dokumentów.
Istnieją cztery wbudowane typy betonowe, które implementują IXmlRepository
:
Aby uzyskać więcej informacji, zobacz dokument dostawcy magazynu kluczy.
Rejestrowanie niestandardowe IXmlRepository
jest odpowiednie w przypadku korzystania z innego magazynu kopii zapasowych (na przykład usługi Azure Table Storage).
Aby zmienić domyślne repozytorium dla całej aplikacji, zarejestruj wystąpienie niestandardowe IXmlRepository
:
services.Configure<KeyManagementOptions>(options => options.XmlRepository = new MyCustomXmlRepository());
services.AddSingleton<IXmlRepository>(new MyCustomXmlRepository());
IXmlEncryptor
Interfejs IXmlEncryptor
reprezentuje typ, który może szyfrować element XML w postaci zwykłego tekstu. Uwidacznia pojedynczy interfejs API:
- Encrypt(XElement plaintextElement) : EncryptedXmlInfo
Jeśli serializowany IAuthenticatedEncryptorDescriptor
zawiera jakiekolwiek elementy oznaczone jako "wymaga szyfrowania", XmlKeyManager
uruchomi te elementy za pomocą skonfigurowanej IXmlEncryptor
Encrypt
metody , a następnie utrwały element zaszyfrowany, a nie element zwykłego tekstu do IXmlRepository
elementu . Dane wyjściowe Encrypt
metody to EncryptedXmlInfo
obiekt. Ten obiekt jest otoką zawierającą zarówno wynikowe zaszyfrowane XElement
, jak i typ, który reprezentuje IXmlDecryptor
element, który może służyć do rozszyfrowania odpowiedniego elementu.
Istnieją cztery wbudowane typy betonowe, które implementują IXmlEncryptor
:
Aby uzyskać więcej informacji, zobacz szyfrowanie kluczy w rest dokumencie.
Aby zmienić domyślny mechanizm szyfrowania kluczy wrest całej aplikacji, zarejestruj wystąpienie niestandardowe IXmlEncryptor
:
services.Configure<KeyManagementOptions>(options => options.XmlEncryptor = new MyCustomXmlEncryptor());
services.AddSingleton<IXmlEncryptor>(new MyCustomXmlEncryptor());
IXmlDecryptor
Interfejs IXmlDecryptor
reprezentuje typ, który wie, jak odszyfrować XElement
element, który został zaszyfrowany za pomocą elementu IXmlEncryptor
. Uwidacznia pojedynczy interfejs API:
- Decrypt(XElement encryptedElement) : XElement
Metoda Decrypt
cofa szyfrowanie wykonywane przez IXmlEncryptor.Encrypt
program . Ogólnie rzecz biorąc, każda konkretna IXmlEncryptor
implementacja będzie miała odpowiednią konkretną IXmlDecryptor
implementację.
Typy, które implementują IXmlDecryptor
, powinny mieć jeden z następujących dwóch konstruktorów publicznych:
- .ctor(IServiceProvider)
- .ctor()
Uwaga
Przekazany IServiceProvider
do konstruktora może mieć wartość null.
IKeyEscrowSink
Interfejs IKeyEscrowSink
reprezentuje typ, który może wykonywać deponowanie poufnych informacji. Pamiętaj, że serializowane deskryptory mogą zawierać poufne informacje (takie jak materiał kryptograficzny), co doprowadziło do wprowadzenia typu IXmlEncryptor w pierwszej kolejności. Jednak zdarzają się wypadki, a pierścienie kluczy można usunąć lub ulec uszkodzeniu.
Interfejs depozytu zapewnia awaryjne wyjście ucieczki, umożliwiając dostęp do nieprzetworzonego serializowanego kodu XML przed przekształceniem przez dowolny skonfigurowany program IXmlEncryptor. Interfejs uwidacznia jeden interfejs API:
- Store(Guid keyId, XElement, element)
IKeyEscrowSink
Do implementacji należy obsługa dostarczonego elementu w bezpieczny sposób zgodny z zasadami biznesowymi. Jedną z możliwych implementacji może być ujście depozytu w celu zaszyfrowania elementu XML przy użyciu znanego firmowego certyfikatu X.509, w którym klucz prywatny certyfikatu został deponowany; typ CertificateXmlEncryptor
może pomóc w tym. Implementacja IKeyEscrowSink
jest również odpowiedzialna za odpowiednie utrwalanie dostarczonego elementu.
Domyślnie żaden mechanizm deponowania nie jest włączony, chociaż administratorzy serwerów mogą skonfigurować tę funkcję globalnie. Można go również skonfigurować programowo za pomocą IDataProtectionBuilder.AddKeyEscrowSink
metody, jak pokazano w poniższym przykładzie. Metoda AddKeyEscrowSink
przeciąża dublowanie IServiceCollection.AddSingleton
przeciążeń i IServiceCollection.AddInstance
, ponieważ IKeyEscrowSink
wystąpienia mają być pojedyncze. Jeśli zarejestrowano wiele IKeyEscrowSink
wystąpień, każdy z nich będzie wywoływany podczas generowania klucza, dzięki czemu klucze mogą być deponowane do wielu mechanizmów jednocześnie.
Nie ma interfejsu API do odczytywania materiału z IKeyEscrowSink
wystąpienia. Jest to zgodne z teorią projektowania mechanizmu deponowania: ma na celu udostępnienie kluczowego materiału zaufanemu urzędowi, a ponieważ aplikacja nie jest zaufanym urzędem, nie powinna mieć dostępu do własnego materiału deponowanego.
Poniższy przykładowy kod demonstruje tworzenie i rejestrowanie IKeyEscrowSink
, w którym klucze są deponowane, tak aby tylko członkowie "ADMINISTRATORZy CONTOSODomain" mogli je odzyskać.
Uwaga
Aby uruchomić ten przykład, musisz być na komputerze z systemem Windows 8 / Windows Server 2012 przyłączonym do domeny, a kontroler domeny musi być systemem Windows Server 2012 lub nowszym.
using System;
using System.IO;
using System.Xml.Linq;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.AspNetCore.DataProtection.XmlEncryption;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
public class Program
{
public static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
.ProtectKeysWithDpapi()
.AddKeyEscrowSink(sp => new MyKeyEscrowSink(sp));
var services = serviceCollection.BuildServiceProvider();
// get a reference to the key manager and force a new key to be generated
Console.WriteLine("Generating new key...");
var keyManager = services.GetService<IKeyManager>();
keyManager.CreateNewKey(
activationDate: DateTimeOffset.Now,
expirationDate: DateTimeOffset.Now.AddDays(7));
}
// A key escrow sink where keys are escrowed such that they
// can be read by members of the CONTOSO\Domain Admins group.
private class MyKeyEscrowSink : IKeyEscrowSink
{
private readonly IXmlEncryptor _escrowEncryptor;
public MyKeyEscrowSink(IServiceProvider services)
{
// Assuming I'm on a machine that's a member of the CONTOSO
// domain, I can use the Domain Admins SID to generate an
// encrypted payload that only they can read. Sample SID from
// https://technet.microsoft.com/library/cc778824(v=ws.10).aspx.
_escrowEncryptor = new DpapiNGXmlEncryptor(
"SID=S-1-5-21-1004336348-1177238915-682003330-512",
DpapiNGProtectionDescriptorFlags.None,
new LoggerFactory());
}
public void Store(Guid keyId, XElement element)
{
// Encrypt the key element to the escrow encryptor.
var encryptedXmlInfo = _escrowEncryptor.Encrypt(element);
// A real implementation would save the escrowed key to a
// write-only file share or some other stable storage, but
// in this sample we'll just write it out to the console.
Console.WriteLine($"Escrowing key {keyId}");
Console.WriteLine(encryptedXmlInfo.EncryptedElement);
// Note: We cannot read the escrowed key material ourselves.
// We need to get a member of CONTOSO\Domain Admins to read
// it for us in the event we need to recover it.
}
}
}
/*
* SAMPLE OUTPUT
*
* Generating new key...
* Escrowing key 38e74534-c1b8-4b43-aea1-79e856a822e5
* <encryptedKey>
* <!-- This key is encrypted with Windows DPAPI-NG. -->
* <!-- Rule: SID=S-1-5-21-1004336348-1177238915-682003330-512 -->
* <value>MIIIfAYJKoZIhvcNAQcDoIIIbTCCCGkCAQ...T5rA4g==</value>
* </encryptedKey>
*/