Konfigurieren des Schutzes von Daten in ASP.NET Core

Wenn das Datenschutzsystem initialisiert wird, wendet es Standardeinstellungen basierend auf der Betriebsumgebung an. Diese Einstellungen sind für Apps geeignet, die auf einem einzelnen Computer ausgeführt werden. Es gibt jedoch Fälle, in denen ein Entwickler möglicherweise die Standardeinstellungen ändern möchte:

  • Die App wird auf mehrere Computer verteilt.
  • Aus Compliancegründen.

Für diese Szenarien bietet das Datenschutzsystem eine umfangreiche Konfigurations-API.

Warnung

Ähnlich wie bei Konfigurationsdateien sollte der Datenschutzschlüsselring mit den entsprechenden Berechtigungen geschützt werden. Sie können sich dafür entscheiden, ruhende Schlüssel zu verschlüsseln, aber dies verhindert nicht, dass Angreifer neue Schlüssel erstellen. Daher wirkt sich die Sicherheit Ihrer App auf die Sicherheit aus. Der mit Datenschutz konfigurierte Speicherort sollte auf die App selbst beschränkt sein, ähnlich wie die Art und Weise, wie Sie Konfigurationsdateien schützen würden. Wenn Sie z. B. den Schlüsselring auf dem Datenträger speichern möchten, verwenden Sie Dateisystemberechtigungen. Stellen Sie sicher, dass nur die Identität, unter der Ihre Web-App ausgeführt wird, lese-, schreib- und erstellen Sie Zugriff auf dieses Verzeichnis. Wenn Sie Azure Blob Storage verwenden, sollte nur die Web-App die Möglichkeit haben, neue Einträge im Blobspeicher zu lesen, zu schreiben oder zu erstellen.

Die Erweiterungsmethode AddDataProtection gibt eine IDataProtectionBuilder. IDataProtectionBuilder macht Erweiterungsmethoden verfügbar, die Sie zusammen verketten können, um Die Datenschutzoptionen zu konfigurieren.

Die folgenden NuGet-Pakete sind für die in diesem Artikel verwendeten Datenschutzerweiterungen erforderlich:

ProtectKeysWithAzureKeyVault

Melden Sie sich mit der CLI bei Azure an, z. B.:

az login

Um Schlüssel in Azure Key Vault zu speichern, konfigurieren Sie das System mit ProtectKeysWithAzureKeyVault in Program.cs. blobUriWithSasToken ist der vollständige URI, in dem die Schlüsseldatei gespeichert werden soll. Der URI muss das SAS-Token als Abfragezeichenfolgenparameter enthalten:

builder.Services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
    .ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());

Damit eine App mit KeyVault kommunizieren und autorisieren kann, muss das Azure-Paket hinzugefügt werden.Identity

Legen Sie den Schlüsselringspeicherort fest (z. B PersistKeysToAzureBlobStorage. ). Der Speicherort muss festgelegt werden, da der Aufruf ProtectKeysWithAzureKeyVault eine Implementierung implementiert IXmlEncryptor , die automatische Datenschutzeinstellungen deaktiviert, einschließlich des Speicherorts des Schlüsselrings. Im vorherigen Beispiel wird Azure Blob Storage verwendet, um den Schlüsselring beizubehalten. Weitere Informationen finden Sie unter Schlüsselspeicheranbieter: Azure Storage. Sie können den Schlüsselring auch lokal mit PersistKeysToFileSystem beibehalten.

Dies keyIdentifier ist der Schlüsseltresorschlüsselbezeichner, der für die Schlüsselverschlüsselung verwendet wird. Ein Schlüssel, der z. B. im Schlüsseltresor mit dataprotectioncontosokeyvault dem Namen "Schlüsselbezeichner" erstellt wurde, weist beispielsweise den Schlüsselbezeichner https://contosokeyvault.vault.azure.net/keys/dataprotection/auf. Stellen Sie die App mit den Berechtigungen "Get", " Entschlüsselungsschlüssel " und " Schlüsselumbruch " für den Schlüsseltresor bereit.

ProtectKeysWithAzureKeyVault Überladungen:

Wenn die App die älteren Azure-Pakete (Microsoft.AspNetCore.DataProtection.AzureStorage und Microsoft.AspNetCore.DataProtection.AzureKeyVault) verwendet, empfehlen wir, diese Verweise zu entfernen und auf azure.Extensions.AspNetCore.DataProtection.Blobs und Azure.Extensions.AspNetCore.DataProtection.Keys zu entfernen. Diese Pakete sind der Ort, an dem neue Updates bereitgestellt werden, und einige wichtige Sicherheits- und Stabilitätsprobleme mit den älteren Paketen behandeln.

builder.Services.AddDataProtection()
    // This blob must already exist before the application is run
    .PersistKeysToAzureBlobStorage("<storageAccountConnectionString", "<containerName>", "<blobName>")
    // Removing this line below for an initial run will ensure the file is created correctly
    .ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());

PersistKeysToFileSystem

Um Schlüssel in einer UNC-Freigabe anstelle des Standardspeicherorts %LOCALAPPDATA% zu speichern, konfigurieren Sie das System mit PersistKeysToFileSystem:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));

Warnung

Wenn Sie den Schlüsselpersistenzspeicherort ändern, verschlüsselt das System nicht mehr automatisch Schlüssel im Ruhezustand, da es nicht weiß, ob DPAPI ein geeigneter Verschlüsselungsmechanismus ist.

PersistKeysToDbContext

Um Schlüssel in einer Datenbank mithilfe von EntityFramework zu speichern, konfigurieren Sie das System mit dem Paket "Microsoft.AspNetCore.DataProtection.EntityFrameworkCore ":

builder.Services.AddDataProtection()
    .PersistKeysToDbContext<SampleDbContext>();

Der vorherige Code speichert die Schlüssel in der konfigurierten Datenbank. Der verwendete Datenbankkontext muss implementiert werden IDataProtectionKeyContext. IDataProtectionKeyContext macht die Eigenschaft verfügbar DataProtectionKeys

public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;

Diese Eigenschaft stellt die Tabelle dar, in der die Schlüssel gespeichert werden. Erstellen Sie die Tabelle manuell oder mit DbContext Migrationen. Weitere Informationen finden Sie unter DataProtectionKey.

ProtectKeysWith*

Sie können das System so konfigurieren, dass Schlüssel ruhende Schlüssel geschützt werden, indem Sie eine der ProtectKeysWith* -Konfigurations-APIs aufrufen. Betrachten Sie das folgende Beispiel, in dem Schlüssel auf einer UNC-Freigabe gespeichert und diese Schlüssel mit einem bestimmten X.509-Zertifikat verschlüsselt werden:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);

Sie können eine X509Certificate2 Datei ProtectKeysWithCertificatebereitstellen, z. B. ein zertifikat, das aus einer Datei geladen wurde:

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .ProtectKeysWithCertificate(
        new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));

Weitere Beispiele und Diskussionen zu den integrierten Schlüsselverschlüsselungsmechanismen finden Sie unter "Key Encryption At Rest ".

UnprotectKeysWithAnyCertificate

Sie können Zertifikate drehen und schlüssel im Ruhezustand entschlüsseln, indem Sie ein Array von X509Certificate2 Zertifikaten UnprotectKeysWithAnyCertificatemit :

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
    .ProtectKeysWithCertificate(
        new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]))
    .UnprotectKeysWithAnyCertificate(
        new X509Certificate2("certificate_1.pfx", builder.Configuration["CertificatePassword_1"]),
        new X509Certificate2("certificate_2.pfx", builder.Configuration["CertificatePassword_2"]));

SetDefaultKeyLifetime

Verwenden Sie SetDefaultKeyLifetimezum Konfigurieren des Systems eine Schlüssellebensdauer von 14 Tagen anstelle der standardmäßigen 90 Tage:

builder.Services.AddDataProtection()
    .SetDefaultKeyLifetime(TimeSpan.FromDays(14));

SetApplicationName

Standardmäßig isoliert das Datenschutzsystem Apps voneinander basierend auf ihren Inhaltsstammpfaden , auch wenn sie dasselbe physische Schlüssel-Repository teilen. Diese Isolation verhindert, dass die Apps die geschützten Nutzlasten miteinander verstehen.

So teilen Sie geschützte Nutzlasten zwischen Apps:

builder.Services.AddDataProtection()
    .SetApplicationName("<sharedApplicationName>");

Warnung

Normalisiert in .NET 6 WebApplicationBuilder den Stammpfad des Inhaltsstamms, um mit einem DirectorySeparatorChar. Beispielsweise endet der Inhaltsstammpfad unter Windows in \ und unter Linux /. Andere Hosts normalisieren den Pfad nicht. Die meisten Apps, die von HostBuilder der App migriert werden oder WebHostBuilder nicht denselben App-Namen teilen, da sie nicht über das Beenden DirectorySeparatorCharverfügen. Um dieses Problem zu umgehen, entfernen Sie das Verzeichnistrennzeichen, und legen Sie den App-Namen manuell fest, wie im folgenden Code gezeigt:

using Microsoft.AspNetCore.DataProtection;
using System.Reflection;

var builder = WebApplication.CreateBuilder(args);
var trimmedContentRootPath = builder.Environment.ContentRootPath.TrimEnd(Path.DirectorySeparatorChar);
builder.Services.AddDataProtection()
 .SetApplicationName(trimmedContentRootPath);
var app = builder.Build();

app.MapGet("/", () => Assembly.GetEntryAssembly()!.GetName().Name);

app.Run();

DisableAutomaticKeyGeneration

Möglicherweise haben Sie ein Szenario, in dem sie nicht möchten, dass eine App automatisch Schlüssel rollt (neue Schlüssel erstellen) während des Ablaufs. Ein Beispiel für dieses Szenario kann die Einrichtung von Apps in einer primären/sekundären Beziehung sein, bei der nur die primäre App für wichtige Verwaltungsbedenken und sekundäre Apps einfach eine schreibgeschützte Ansicht des Schlüsselrings hat. Die sekundären Apps können so konfiguriert werden, dass der Schlüsselring schreibgeschützt behandelt wird, indem sie das System mit DisableAutomaticKeyGeneration:

builder.Services.AddDataProtection()
    .DisableAutomaticKeyGeneration();

Isolation pro Anwendung

Wenn das Datenschutzsystem von einem ASP.NET Core Host bereitgestellt wird, isoliert es Apps automatisch voneinander, auch wenn diese Apps unter demselben Arbeitsprozesskonto ausgeführt werden und dasselbe Masterschlüsselmaterial verwenden. Dies ähnelt dem IsolateApps-Modifizierer aus dem System.Web-Element <machineKey> .

Der Isolationsmechanismus funktioniert, indem jede App auf dem lokalen Computer als eindeutiger Mandant betrachtet wird, soweit dies IDataProtector für jede bestimmte App automatisch die App-ID als Diskriminator enthält. Die eindeutige ID der App ist der physische Pfad der App:

  • Bei Apps, die in IIS gehostet werden, ist die eindeutige ID der physische IIS-Pfad der App. Wenn eine App in einer Webfarmumgebung bereitgestellt wird, ist dieser Wert stabil, vorausgesetzt, dass die IIS-Umgebungen auf allen Computern in der Webfarm ähnlich konfiguriert sind.
  • Für selbst gehostete Apps, die auf dem Kestrel Server ausgeführt werden, ist die eindeutige ID der physische Pfad zur App auf dem Datenträger.

Der eindeutige Bezeichner ist darauf ausgelegt, Resets zu überleben – sowohl der einzelnen App als auch des Computers selbst.

Dieser Isolationsmechanismus geht davon aus, dass die Apps nicht böswillig sind. Eine schädliche App kann sich immer auf alle anderen Apps auswirken, die unter demselben Arbeitsprozesskonto ausgeführt werden. In einer freigegebenen Hostingumgebung, in der Apps gegenseitig nicht vertrauenswürdig sind, sollte der Hostinganbieter Schritte ausführen, um die Isolation auf Betriebssystemebene zwischen Apps sicherzustellen, einschließlich der Trennung der zugrunde liegenden Schlüsselrepositorys der Apps.

Wenn das Datenschutzsystem nicht von einem ASP.NET Core Host bereitgestellt wird (z. B. wenn Sie es über den konkreten Typ instanziieren), ist die DataProtectionProvider App-Isolation standardmäßig deaktiviert. Wenn die App-Isolation deaktiviert ist, können alle Apps, die von demselben Schlüsselmaterial unterstützt werden, Nutzlasten freigeben, solange sie die entsprechenden Zwecke bereitstellen. Rufen Sie zum Bereitstellen der App-Isolation in dieser Umgebung die SetApplicationName-Methode für das Konfigurationsobjekt auf, und geben Sie für jede App einen eindeutigen Namen an.

Datenschutz und App-Isolation

Berücksichtigen Sie die folgenden Punkte für die App-Isolation:

  • Wenn mehrere Apps auf dasselbe Schlüssel-Repository verweisen, ist die Absicht, dass die Apps das gleiche Masterschlüsselmaterial teilen. Der Datenschutz wird mit der Annahme entwickelt, dass alle Apps, die einen Schlüsselring teilen, auf alle Elemente in diesem Schlüsselring zugreifen können. Der eindeutige Bezeichner der Anwendung wird verwendet, um anwendungsspezifische Schlüssel zu isolieren, die von dem bereitgestellten Schlüsselring abgeleitet wurden. Es erwartet keine Berechtigungen auf Elementebene, z. B. die von Azure KeyVault bereitgestellten Berechtigungen, um zusätzliche Isolation zu erzwingen. Beim Versuch von Berechtigungen auf Elementebene werden Anwendungsfehler generiert. Wenn Sie sich nicht auf die integrierte Anwendungsisolation verlassen möchten, sollten separate Schlüsselspeicherorte verwendet und nicht zwischen Anwendungen freigegeben werden.

  • Der Anwendungsdiskriminator wird verwendet, um verschiedenen Apps das gleiche Masterschlüsselmaterial zu ermöglichen, aber ihre kryptografischen Nutzlasten voneinander unterscheiden zu lassen. Damit die Apps die kryptografischen Nutzlasten gegenseitig lesen können, müssen sie dieselbe Anwendungsdiskriminator haben.

  • Wenn eine App kompromittiert ist (z. B. durch einen RCE-Angriff), müssen alle Masterschlüsselmaterial, auf das diese App zugreifen kann, auch als kompromittiert betrachtet werden, unabhängig von ihrem Schutzzustand. Dies bedeutet, dass, wenn zwei Apps auf dasselbe Repository verweisen, auch wenn sie unterschiedliche App-Diskriminatoren verwenden, eine Kompromittierung eines von beiden funktionell gleichwertig ist.

    Diese "funktionell gleichwertige" Klausel enthält auch dann, wenn die beiden Apps unterschiedliche Mechanismen für den ruhenden Schlüsselschutz verwenden. In der Regel ist dies keine erwartete Konfiguration. Der Schutz-at-Rest-Mechanismus soll Schutz bieten, wenn ein Angreifer lesezugriff auf das Repository erhält. Ein Angreifer, der Schreibzugriff auf das Repository erhält (vielleicht weil er die Codeausführungsberechtigung in einer App erreicht hat) kann böswillige Schlüssel in den Speicher einfügen. Das Datenschutzsystem bietet absichtlich keinen Schutz vor einem Angreifer, der Schreibzugriff auf das Schlüsselreppository erhält.

  • Wenn Apps wirklich isoliert bleiben müssen, sollten sie verschiedene Schlüsselrepositorys verwenden. Dies fällt natürlich aus der Definition von "isoliert". Apps sind nicht isoliert, wenn sie alle über Lese- und Schreibzugriff auf die Datenspeicher des anderen verfügen.

Ändern von Algorithmen mit UseCryptographicAlgorithms

Mit dem Datenschutzstapel können Sie den Standardalgorithmus ändern, der von neu generierten Schlüsseln verwendet wird. Die einfachste Möglichkeit hierfür ist das Aufrufen UseCryptographicAlgorithms aus dem Konfigurationsrückruf:

builder.Services.AddDataProtection()
    .UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
    {
        EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
        ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
    });

Die StandardverschlüsselungAlgorithm ist AES-256-CBC, und die StandardüberprüfungAlgorithm ist HMACSHA256. Die Standardrichtlinie kann von einem Systemadministrator über eine computerweite Richtlinie festgelegt werden, aber ein expliziter Aufruf, um die Standardrichtlinie außer Kraft zu UseCryptographicAlgorithms setzen.

Durch aufrufen UseCryptographicAlgorithms können Sie den gewünschten Algorithmus aus einer vordefinierten integrierten Liste angeben. Sie müssen sich keine Gedanken über die Implementierung des Algorithmus machen. Im obigen Szenario versucht das Datenschutzsystem, die CNG-Implementierung von AES bei Ausführung unter Windows zu verwenden. Andernfalls fällt er auf die verwaltete System.Security.Cryptography.Aes Klasse zurück.

Sie können eine Implementierung manuell über einen Aufruf angeben.UseCustomCryptographicAlgorithms

Tipp

Das Ändern von Algorithmen wirkt sich nicht auf vorhandene Schlüssel im Tastenring aus. Es wirkt sich nur auf neu generierte Schlüssel aus.

Angeben benutzerdefinierter verwalteter Algorithmen

Um benutzerdefinierte verwaltete Algorithmen anzugeben, erstellen Sie eine ManagedAuthenticatedEncryptorConfiguration Instanz, die auf die Implementierungstypen verweist:

builder.Services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(new ManagedAuthenticatedEncryptorConfiguration
    {
        // A type that subclasses SymmetricAlgorithm
        EncryptionAlgorithmType = typeof(Aes),

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

        // A type that subclasses KeyedHashAlgorithm
        ValidationAlgorithmType = typeof(HMACSHA256)
    });

Im Allgemeinen müssen die *Type-Eigenschaften auf konkrete, instanziierbare Implementierungen SymmetricAlgorithm (über einen öffentlichen parameterlosen Ctor) verweisen, KeyedHashAlgorithmobwohl die Systemspezifischen Fälle einige Werte wie typeof(Aes) komfortlos sind.

Hinweis

Die SymmetricAlgorithm muss eine Schlüssellänge von ≥ 128 Bit und eine Blockgröße von ≥ 64 Bits aufweisen, und sie muss die CBC-Modus-Verschlüsselung mit PKCS #7 Abstand unterstützen. Der KeyedHashAlgorithm muss eine Digestgröße von >= 128 Bit aufweisen, und er muss Schlüssel der Länge unterstützen, die der Digestlänge des Hashalgorithmus entsprechen. Der KeyedHashAlgorithm ist nicht unbedingt erforderlich, um HMAC zu sein.

Angeben von benutzerdefinierten Windows CNG-Algorithmen

Um einen benutzerdefinierten Windows CNG-Algorithmus mit CBC-Modus-Verschlüsselung mit HMAC-Validierung anzugeben, erstellen Sie eine CngCbcAuthenticatedEncryptorConfiguration Instanz, die die algorithmusischen Informationen enthält:

builder.Services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(new CngCbcAuthenticatedEncryptorConfiguration
    {
        // Passed to BCryptOpenAlgorithmProvider
        EncryptionAlgorithm = "AES",
        EncryptionAlgorithmProvider = null,

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

        // Passed to BCryptOpenAlgorithmProvider
        HashAlgorithm = "SHA256",
        HashAlgorithmProvider = null
    });

Hinweis

Der symmetrische Blockchiffrealgorithmus muss eine Schlüssellänge von >= 128 Bit, eine Blockgröße von >= 64 Bit aufweisen und die CBC-Modus-Verschlüsselung mit PKCS #7 Abstand unterstützen. Der Hashalgorithmus muss eine Digestgröße von >= 128 Bit aufweisen und das Öffnen mit dem BCRYPT_ALG_HANDLE_HMAC_FLAG Flag unterstützen. Die *Provider-Eigenschaften können auf NULL festgelegt werden, um den Standardanbieter für den angegebenen Algorithmus zu verwenden. Weitere Informationen finden Sie in der Dokumentation zu BCryptOpenAlgorithmProvider .

Um einen benutzerdefinierten Windows CNG-Algorithmus mit Galois/Counter Mode-Verschlüsselung mit Überprüfung anzugeben, erstellen Sie eine CngGcmAuthenticatedEncryptorConfiguration Instanz, die die algorithmusischen Informationen enthält:

builder.Services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(new CngGcmAuthenticatedEncryptorConfiguration
    {
        // Passed to BCryptOpenAlgorithmProvider
        EncryptionAlgorithm = "AES",
        EncryptionAlgorithmProvider = null,

        // Specified in bits
        EncryptionAlgorithmKeySize = 256
    });

Hinweis

Der symmetrische Blockchiffrealgorithmus muss eine Schlüssellänge von >= 128 Bit, eine Blockgröße von genau 128 Bit aufweisen und die GCM-Verschlüsselung unterstützen. Sie können die EncryptionAlgorithmProvider Eigenschaft auf NULL festlegen, um den Standardanbieter für den angegebenen Algorithmus zu verwenden. Weitere Informationen finden Sie in der Dokumentation zu BCryptOpenAlgorithmProvider .

Angeben anderer benutzerdefinierter Algorithmen

Obwohl das Datenschutzsystem nicht als erstklassige API verfügbar gemacht wird, ist das Datenschutzsystem erweiterbar genug, um die Angabe fast jeder Art von Algorithmus zu ermöglichen. So ist es beispielsweise möglich, alle Schlüssel in einem Hardware Security Module (HSM) beizubehalten und eine benutzerdefinierte Implementierung der Kernverschlüsselungs- und Entschlüsselungsroutinen bereitzustellen. Weitere Informationen finden Sie in IAuthenticatedEncryptor der Erweiterbarkeit der Kern kryptografie.

Beibehalten von Schlüsseln beim Hosten in einem Docker-Container

Beim Hosten in einem Docker-Container sollten Schlüssel in einer der folgenden Aktionen verwaltet werden:

  • Ein Ordner, der ein Docker-Volume ist, das über die Lebensdauer des Containers hinaus besteht, z. B. ein freigegebenes Volume oder ein hostgemountetes Volume.
  • Ein externer Anbieter, z. B. Azure Blob Storage (im ProtectKeysWithAzureKeyVault Abschnitt dargestellt) oder Redis.

Beibehalten von Schlüsseln mit Redis

Nur Redis-Versionen, die Redis-Datenpersistenz unterstützen, sollten zum Speichern von Schlüsseln verwendet werden. Azure Blob Storage ist beständig und kann zum Speichern von Schlüsseln verwendet werden. Weitere Informationen finden Sie in diesem GitHub-Issue.

Protokollierung von DataProtection

Aktivieren Sie Information die Protokollierung der Ebene von DataProtection, um Diagnoseproblem zu unterstützen. Die folgende appsettings.json Datei ermöglicht die Informationsprotokollierung der DataProtection-API:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.DataProtection": "Information"
    }
  },
  "AllowedHosts": "*"
}

Weitere Informationen zur Protokollierung finden Sie unter Protokollierung in .NET Core und ASP.NET Core.

Zusätzliche Ressourcen

Wenn das Datenschutzsystem initialisiert wird, wendet es Standardeinstellungen basierend auf der Betriebsumgebung an. Diese Einstellungen sind für Apps geeignet, die auf einem einzelnen Computer ausgeführt werden. Es gibt jedoch Fälle, in denen ein Entwickler möglicherweise die Standardeinstellungen ändern möchte:

  • Die App wird auf mehrere Computer verteilt.
  • Aus Compliancegründen.

Für diese Szenarien bietet das Datenschutzsystem eine umfangreiche Konfigurations-API.

Warnung

Ähnlich wie bei Konfigurationsdateien sollte der Datenschutzschlüsselring mit den entsprechenden Berechtigungen geschützt werden. Sie können sich dafür entscheiden, ruhende Schlüssel zu verschlüsseln, aber dies verhindert nicht, dass Angreifer neue Schlüssel erstellen. Daher wirkt sich die Sicherheit Ihrer App auf die Sicherheit aus. Der mit Datenschutz konfigurierte Speicherort sollte auf die App selbst beschränkt sein, ähnlich wie die Art und Weise, wie Sie Konfigurationsdateien schützen würden. Wenn Sie z. B. den Schlüsselring auf dem Datenträger speichern möchten, verwenden Sie Dateisystemberechtigungen. Stellen Sie sicher, dass nur die Identität, unter der Ihre Web-App ausgeführt wird, lese-, schreib- und erstellen Sie Zugriff auf dieses Verzeichnis. Wenn Sie Azure Blob Storage verwenden, sollte nur die Web-App die Möglichkeit haben, neue Einträge im Blobspeicher zu lesen, zu schreiben oder zu erstellen.

Die Erweiterungsmethode AddDataProtection gibt eine IDataProtectionBuilder. IDataProtectionBuilder macht Erweiterungsmethoden verfügbar, die Sie zusammen verketten können, um Die Datenschutzoptionen zu konfigurieren.

Die folgenden NuGet-Pakete sind für die in diesem Artikel verwendeten Datenschutzerweiterungen erforderlich:

ProtectKeysWithAzureKeyVault

Melden Sie sich mit der CLI bei Azure an, z. B.:

az login

Um Schlüssel in Azure Key Vault zu speichern, konfigurieren Sie das System mit ProtectKeysWithAzureKeyVault der Startup Klasse. blobUriWithSasToken ist der vollständige URI, in dem die Schlüsseldatei gespeichert werden soll. Der URI muss das SAS-Token als Abfragezeichenfolgenparameter enthalten:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
        .ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());
}

Damit eine App mit KeyVault kommunizieren und autorisieren kann, muss das Azure-Paket hinzugefügt werden.Identity

Legen Sie den Schlüsselringspeicherort fest (z. B PersistKeysToAzureBlobStorage. ). Der Speicherort muss festgelegt werden, da der Aufruf ProtectKeysWithAzureKeyVault eine Implementierung implementiert IXmlEncryptor , die automatische Datenschutzeinstellungen deaktiviert, einschließlich des Speicherorts des Schlüsselrings. Im vorherigen Beispiel wird Azure Blob Storage verwendet, um den Schlüsselring beizubehalten. Weitere Informationen finden Sie unter Schlüsselspeicheranbieter: Azure Storage. Sie können den Schlüsselring auch lokal mit PersistKeysToFileSystem beibehalten.

Dies keyIdentifier ist der Schlüsselschlüsselbezeichner, der für die Schlüsselverschlüsselung verwendet wird. Beispielsweise hat ein Schlüssel, der im Schlüsseltresor mit dem dataprotection Namen des contosokeyvault Schlüsselbezeichners https://contosokeyvault.vault.azure.net/keys/dataprotection/erstellt wurde. Stellen Sie die App mit Den Berechtigungen "Get", " Unwrap Key " und "Umbruchschlüssel " für den Schlüsseltresor bereit.

ProtectKeysWithAzureKeyVault Überladungen:

Wenn die App die älteren Azure-Pakete (Microsoft.AspNetCore.DataProtection.AzureStorage und Microsoft.AspNetCore.DataProtection.AzureKeyVault) verwendet, empfehlen wir, diese Verweise zu entfernen und auf die Azure.Extensions.AspNetCore.DataProtection.Blobs und Azure.Extensions.AspNetCore.DataProtection.Keys zu entfernen. Diese Pakete werden bereitgestellt, und es werden einige wichtige Sicherheits- und Stabilitätsprobleme mit den älteren Paketen behandelt.

services.AddDataProtection()
    //This blob must already exist before the application is run
    .PersistKeysToAzureBlobStorage("<storage account connection string", "<key store container name>", "<key store blob name>")
    //Removing this line below for an initial run will ensure the file is created correctly
    .ProtectKeysWithAzureKeyVault(new Uri("<keyIdentifier>"), new DefaultAzureCredential());

PersistKeysToFileSystem

Um Schlüssel in einer UNC-Freigabe anstelle des Standardspeicherorts %LOCALAPPDATA% zu speichern, konfigurieren Sie das System mit PersistKeysToFileSystem:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
}

Warnung

Wenn Sie den Schlüsselbeharrungsort ändern, verschlüsselt das System die Schlüssel nicht mehr automatisch, da sie nicht weiß, ob DPAPI ein geeignetes Verschlüsselungsmechanismus ist.

PersistKeysToDbContext

Um Schlüssel in einer Datenbank mithilfe von EntityFramework zu speichern, konfigurieren Sie das System mit dem Microsoft.AspNetCore.DataProtection.EntityFrameworkCore-Paket :

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToDbContext<DbContext>()
}

Der vorherige Code speichert die Schlüssel in der konfigurierten Datenbank. Der verwendete Datenbankkontext muss implementiert IDataProtectionKeyContextwerden. IDataProtectionKeyContext stellt die Eigenschaft zur Verfügung. DataProtectionKeys

public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }

Diese Eigenschaft stellt die Tabelle dar, in der die Schlüssel gespeichert werden. Erstellen Sie die Tabelle manuell oder mit DbContext Migrationen. Weitere Informationen finden Sie unter DataProtectionKey.

ProtectKeysWith*

Sie können das System so konfigurieren, dass Schlüssel zur Ruhe geschützt werden, indem Sie eine der ProtectKeysWith* -Konfigurations-APIs aufrufen. Betrachten Sie das folgende Beispiel, das Schlüssel in einer UNC-Freigabe speichert und diese Schlüssel mit einem bestimmten X.509-Zertifikat verschlüsselt:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
        .ProtectKeysWithCertificate(Configuration["Thumbprint"]);
}

Sie können eine X509Certificate2 Datei ProtectKeysWithCertificateangeben, z. B. ein zertifikat, das aus einer Datei geladen wurde:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
        .ProtectKeysWithCertificate(
            new X509Certificate2("certificate.pfx", Configuration["Thumbprint"]));
}

Weitere Beispiele und Diskussionen zu den integrierten Schlüsselverschlüsselungsmechanismen finden Sie unter "Key Encryption At Rest ".

UnprotectKeysWithAnyCertificate

Sie können Zertifikate und Entschlüsselungsschlüssel ruhen, indem Sie ein Array von X509Certificate2 Zertifikaten UnprotectKeysWithAnyCertificatemit :

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
        .ProtectKeysWithCertificate(
            new X509Certificate2("certificate.pfx", Configuration["MyPasswordKey"));
        .UnprotectKeysWithAnyCertificate(
            new X509Certificate2("certificate_old_1.pfx", Configuration["MyPasswordKey_1"]),
            new X509Certificate2("certificate_old_2.pfx", Configuration["MyPasswordKey_2"]));
}

SetDefaultKeyLifetime

Um das System zu konfigurieren, um eine Schlüssellebensdauer von 14 Tagen anstelle der Standardzeit von 90 Tagen zu verwenden, verwenden Sie SetDefaultKeyLifetime:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .SetDefaultKeyLifetime(TimeSpan.FromDays(14));
}

SetApplicationName

Standardmäßig isoliert das Datenschutzsystem Apps von einem anderen basierend auf ihren Inhaltsstammpfaden , auch wenn sie das gleiche physische Schlüssel-Repository teilen. Diese Isolation verhindert, dass die Apps die geschützten Nutzlasten miteinander verstehen.

So teilen Sie geschützte Nutzlasten in Apps mit:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .SetApplicationName("shared app name");
}

DisableAutomaticKeyGeneration

Möglicherweise haben Sie ein Szenario, in dem Sie keine App möchten, dass die Tasten automatisch rollt (neue Schlüssel erstellen), da sie ablaufen. Ein Beispiel dieses Szenarios ist möglicherweise Apps, die in einer primären/sekundären Beziehung eingerichtet sind, wobei nur die primäre App für die Schlüsselverwaltung und sekundäre Apps eine schreibgeschützte Ansicht des Schlüsselrings hat. Die sekundären Apps können so konfiguriert werden, dass der Schlüsselring als schreibgeschützt behandelt wird, indem Sie das System mit DisableAutomaticKeyGeneration:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .DisableAutomaticKeyGeneration();
}

Isolation pro Anwendung

Wenn das Datenschutzsystem von einem ASP.NET Core Host bereitgestellt wird, isoliert er Apps automatisch von einem anderen, auch wenn diese Apps unter demselben Arbeitsprozesskonto ausgeführt werden und das gleiche Masterschlüsselmaterial verwenden. Dies ähnelt dem IsolateApps-Modifier von System.Web's <machineKey> Element.

Der Isolationsmechanismus funktioniert, indem jede App auf dem lokalen Computer als eindeutiger Mandant betrachtet wird, wodurch die IDataProtector wurzelnde App automatisch die App-ID als Diskriminator enthält. Die eindeutige ID der App ist der physische Pfad der App:

  • Für Apps, die in IIS gehostet werden, ist die eindeutige ID der IIS-physische Pfad der App. Wenn eine App in einer Webfarmumgebung bereitgestellt wird, ist dieser Wert stabil, vorausgesetzt, dass die IIS-Umgebungen in allen Computern in der Webfarm ähnlich konfiguriert sind.
  • Für selbst gehostete Apps, die auf dem Kestrel Server ausgeführt werden, ist die eindeutige ID der physische Pfad zur App auf dem Datenträger.

Der eindeutige Bezeichner ist so konzipiert, dass Ersetzungen überleben kann – sowohl von der einzelnen App als auch von dem Computer selbst.

Dieser Isolationsmechanismus geht davon aus, dass die Apps nicht böswillig sind. Eine böswillige App kann sich immer auf alle anderen Apps auswirken, die unter demselben Arbeitsprozesskonto ausgeführt werden. In einer freigegebenen Hostingumgebung, in der Apps gegenseitig nicht vertrauenswürdig sind, sollte der Hostinganbieter Schritte ausführen, um die Isolation auf Betriebssystemebene zwischen Apps zu gewährleisten, einschließlich der Trennung der zugrunde liegenden Schlüsselrepositorys der Apps.

Wenn das Datenschutzsystem nicht von einem ASP.NET Core-Host bereitgestellt wird (z. B. wenn Sie sie über den DataProtectionProvider konkreten Typ instanziieren), ist die App-Isolation standardmäßig deaktiviert. Wenn die App-Isolation deaktiviert ist, können alle Apps, die von demselben Schlüsselmaterial unterstützt werden, Nutzlasten freigeben, solange sie die entsprechenden Zwecke bereitstellen. Um die App-Isolation in dieser Umgebung bereitzustellen, rufen Sie die SetApplicationName-Methode im Konfigurationsobjekt auf, und geben Sie einen eindeutigen Namen für jede App an.

Datenschutz und App-Isolation

Berücksichtigen Sie die folgenden Punkte für die App-Isolation:

  • Wenn mehrere Apps auf das gleiche Schlüssel-Repository verwiesen werden, ist die Absicht, dass die Apps das gleiche Masterschlüsselmaterial teilen. Der Datenschutz wird mit der Annahme entwickelt, dass alle Apps, die einen Schlüsselring freigeben, auf alle Elemente in diesem Schlüsselring zugreifen können. Der eindeutige Bezeichner der Anwendung wird verwendet, um anwendungsspezifische Schlüssel zu isolieren, die aus dem bereitgestellten Schlüsselring abgeleitet wurden. Es erwartet nicht die Berechtigungen auf Elementebene, z. B. die von Azure KeyVault bereitgestellten Berechtigungen, um zusätzliche Isolation zu erzwingen. Beim Versuch von Berechtigungen auf Elementebene werden Anwendungsfehler generiert. Wenn Sie sich nicht auf die integrierte Anwendungsisolation verlassen möchten, sollten separate Schlüsselspeicherspeicherorte verwendet und nicht zwischen Anwendungen freigegeben werden.

  • Die Anwendung diskriminator wird verwendet, um verschiedenen Apps das gleiche Masterschlüsselmaterial zu ermöglichen, aber ihre kryptografischen Nutzlasten voneinander unterscheiden zu lassen. Damit die Apps die kryptografischen Nutzlasten des anderen lesen können, müssen sie dieselbe Anwendungsdiskriminator haben.

  • Wenn eine App kompromittiert ist (z. B. durch einen RCE-Angriff), müssen alle Masterschlüsselmaterial, auf das diese App zugreifen kann, auch als kompromittiert betrachtet werden, unabhängig von ihrem Schutz-at-Rest-Zustand. Dies bedeutet, dass zwei Apps auf das gleiche Repository verweisen, auch wenn sie unterschiedliche App-Diskriminatoren verwenden, eine Kompromittanz von einer funktionell äquivalent zu einem Kompromitt von beiden.

    Diese "funktionell gleichwertige" Klausel enthält auch dann, wenn die beiden Apps unterschiedliche Mechanismen zum Ruheschutz verwenden. In der Regel ist dies keine erwartete Konfiguration. Der Schutz-at-Rest-Mechanismus soll Schutz bieten, wenn ein Gegner Lesezugriff auf das Repository erhält. Ein Gegner, der Schreibzugriff auf das Repository erhält (vielleicht weil sie die Codeausführungsberechtigung in einer App erreicht haben) kann böswillige Schlüssel in den Speicher einfügen. Das Datenschutzsystem bietet absichtlich keinen Schutz vor einem Gegner, der Schreibzugriff auf das Schlüssel-Repository erhält.

  • Wenn Apps wirklich isoliert bleiben müssen, sollten sie verschiedene Schlüsselrepositorys verwenden. Dies fällt natürlich aus der Definition von "isoliert". Apps sind nicht isoliert, wenn sie alle über Lese- und Schreibzugriff auf die Datenspeicher des anderen verfügen.

Ändern von Algorithmen mit UseCryptographicAlgorithms

Mit dem Datenschutzstapel können Sie den Standardalgorithmus ändern, der von neu generierten Schlüsseln verwendet wird. Die einfachste Möglichkeit, dies zu tun, besteht darin, aus dem Konfigurationsrückruf aufzurufen UseCryptographicAlgorithms :

services.AddDataProtection()
    .UseCryptographicAlgorithms(
        new AuthenticatedEncryptorConfiguration()
    {
        EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
        ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
    });

Die StandardverschlüsselungAlgorithm ist AES-256-CBC, und die StandardüberprüfungAlgorithm ist HMACSHA256. Die Standardrichtlinie kann von einem Systemadministrator über eine computerweite Richtlinie festgelegt werden, aber ein expliziter Aufruf, um die Standardrichtlinie außer Kraft zu UseCryptographicAlgorithms setzen.

Durch Aufrufen UseCryptographicAlgorithms können Sie den gewünschten Algorithmus aus einer vordefinierten integrierten Liste angeben. Sie müssen sich nicht um die Implementierung des Algorithmus kümmern. Im obigen Szenario versucht das Datenschutzsystem, die CNG-Implementierung von AES zu verwenden, wenn sie unter Windows ausgeführt wird. Andernfalls fällt er auf die verwaltete System.Security.Cryptography.Aes Klasse zurück.

Sie können eine Implementierung manuell über einen Aufruf UseCustomCryptographicAlgorithmsangeben.

Tipp

Das Ändern von Algorithmen wirkt sich nicht auf vorhandene Schlüssel im Tastenring aus. Es wirkt sich nur auf neu generierte Schlüssel aus.

Angeben von benutzerdefinierten verwalteten Algorithmen

Um benutzerdefinierte verwaltete Algorithmen anzugeben, erstellen Sie eine ManagedAuthenticatedEncryptorConfiguration Instanz, die auf die Implementierungstypen verweist:

serviceCollection.AddDataProtection()
    .UseCustomCryptographicAlgorithms(
        new ManagedAuthenticatedEncryptorConfiguration()
    {
        // A type that subclasses SymmetricAlgorithm
        EncryptionAlgorithmType = typeof(Aes),

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

        // A type that subclasses KeyedHashAlgorithm
        ValidationAlgorithmType = typeof(HMACSHA256)
    });

In der Regel müssen die *Type-Eigenschaften auf konkrete, instanziierbare (über eine öffentliche parameterlose Ctor)-Implementierungen SymmetricAlgorithm verweisen und KeyedHashAlgorithm, obwohl das System einige Werte wie typeof(Aes) für die Bequemlichkeit speziellen Werte aufweist.

Hinweis

Die SymmetricAlgorithm muss eine Schlüssellänge von ≥ 128 Bit und eine Blockgröße von ≥ 64 Bit aufweisen und die CBC-Modusverschlüsselung mit PKCS #7 Padding unterstützen. Der KeyedHashAlgorithm muss eine Digestgröße von >= 128 Bit aufweisen, und es muss Schlüssel der Länge unterstützen, die der Digestlänge des Hash-Algorithmus entspricht. Die KeyedHashAlgorithm ist nicht streng erforderlich, um HMAC zu sein.

Angeben von benutzerdefinierten Windows CNG-Algorithmen

Um einen benutzerdefinierten Windows CNG-Algorithmus mit der CBC-Modus-Verschlüsselung mit der HMAC-Validierung anzugeben, erstellen Sie eine CngCbcAuthenticatedEncryptorConfiguration Instanz, die die algorithmusischen Informationen enthält:

services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(
        new CngCbcAuthenticatedEncryptorConfiguration()
    {
        // Passed to BCryptOpenAlgorithmProvider
        EncryptionAlgorithm = "AES",
        EncryptionAlgorithmProvider = null,

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

        // Passed to BCryptOpenAlgorithmProvider
        HashAlgorithm = "SHA256",
        HashAlgorithmProvider = null
    });

Hinweis

Der symmetrische Blockchiffrealgorithmus muss eine Schlüssellänge von >= 128 Bit, eine Blockgröße von >= 64 Bit aufweisen und die CBC-Modus-Verschlüsselung mit PKCS #7 Abstand unterstützen. Der Hashalgorithmus muss eine Digestgröße von >= 128 Bit aufweisen und das Öffnen mit dem BCRYPT_ALG_HANDLE_HMAC_FLAG Flag unterstützen. Die *Provider-Eigenschaften können auf NULL festgelegt werden, um den Standardanbieter für den angegebenen Algorithmus zu verwenden. Weitere Informationen finden Sie in der Dokumentation zu BCryptOpenAlgorithmProvider .

Um einen benutzerdefinierten Windows CNG-Algorithmus mit Galois/Counter Mode-Verschlüsselung mit Überprüfung anzugeben, erstellen Sie eine CngGcmAuthenticatedEncryptorConfiguration Instanz, die die algorithmusischen Informationen enthält:

services.AddDataProtection()
    .UseCustomCryptographicAlgorithms(
        new CngGcmAuthenticatedEncryptorConfiguration()
    {
        // Passed to BCryptOpenAlgorithmProvider
        EncryptionAlgorithm = "AES",
        EncryptionAlgorithmProvider = null,

        // Specified in bits
        EncryptionAlgorithmKeySize = 256
    });

Hinweis

Der symmetrische Blockchiffrealgorithmus muss eine Schlüssellänge von >= 128 Bit, eine Blockgröße von genau 128 Bit aufweisen und die GCM-Verschlüsselung unterstützen. Sie können die EncryptionAlgorithmProvider Eigenschaft auf NULL festlegen, um den Standardanbieter für den angegebenen Algorithmus zu verwenden. Weitere Informationen finden Sie in der Dokumentation zu BCryptOpenAlgorithmProvider .

Angeben anderer benutzerdefinierter Algorithmen

Obwohl das Datenschutzsystem nicht als erstklassige API verfügbar gemacht wird, ist das Datenschutzsystem erweiterbar genug, um die Angabe fast jeder Art von Algorithmus zu ermöglichen. So ist es beispielsweise möglich, alle Schlüssel in einem Hardware Security Module (HSM) beizubehalten und eine benutzerdefinierte Implementierung der Kernverschlüsselungs- und Entschlüsselungsroutinen bereitzustellen. Weitere Informationen finden Sie in IAuthenticatedEncryptor der Erweiterbarkeit der Kern kryptografie.

Beibehalten von Schlüsseln beim Hosten in einem Docker-Container

Beim Hosten in einem Docker-Container sollten Schlüssel in einer der folgenden Aktionen verwaltet werden:

  • Ein Ordner, der ein Docker-Volume ist, das über die Lebensdauer des Containers hinaus besteht, z. B. ein freigegebenes Volume oder ein hostgemountetes Volume.
  • Ein externer Anbieter, z. B. Azure Blob Storage (im ProtectKeysWithAzureKeyVault Abschnitt dargestellt) oder Redis.

Beibehalten von Schlüsseln mit Redis

Nur Redis-Versionen, die Redis-Datenpersistenz unterstützen, sollten zum Speichern von Schlüsseln verwendet werden. Azure Blob Storage ist beständig und kann zum Speichern von Schlüsseln verwendet werden. Weitere Informationen finden Sie in diesem GitHub-Issue.

Protokollierung von DataProtection

Aktivieren Sie Information die Protokollierung der Ebene von DataProtection, um Diagnoseproblem zu unterstützen. Die folgende appsettings.json Datei ermöglicht die Informationsprotokollierung der DataProtection-API:

{
  "Logging": {
    "LogLevel": {
      "Microsoft.AspNetCore.DataProtection": "Information"
    }
  }
}

Weitere Informationen zur Protokollierung finden Sie unter Protokollierung in .NET Core und ASP.NET Core.

Zusätzliche Ressourcen