Condividi tramite


Configurare la protezione dati di ASP.NET Core

Quando il sistema di protezione dati viene inizializzato, applica le impostazioni predefinite in base all'ambiente operativo. Queste impostazioni sono appropriate per le app in esecuzione in un singolo computer. Tuttavia, esistono casi in cui uno sviluppatore può voler modificare le impostazioni predefinite:

  • L'app viene distribuita in più computer.
  • Per motivi di conformità.

Per questi scenari, il sistema di protezione dei dati offre un'API di configurazione avanzata.

Avviso

Analogamente ai file di configurazione, l'anello della chiave di protezione dei dati deve essere protetto usando le autorizzazioni appropriate. È possibile scegliere di crittografare le chiavi inattive, ma ciò non impedisce ai cyberattacker di creare nuove chiavi. Di conseguenza, la sicurezza dell'app è interessata. Il percorso di archiviazione configurato con Protezione dati deve avere accesso limitato all'app stessa, in modo analogo al modo in cui si proteggerebbero i file di configurazione. Ad esempio, se si sceglie di archiviare l'anello di chiave su disco, usare le autorizzazioni del file system. Assicurati che solo l'identità con cui viene eseguita l'app web abbia accesso in lettura e scrittura a tale directory. Se si usa Archiviazione BLOB di Azure, solo l'app Web deve avere la possibilità di leggere, scrivere o creare nuove voci nell'archivio BLOB e così via.

Il metodo AddDataProtection di estensione restituisce un oggetto IDataProtectionBuilder. IDataProtectionBuilder espone i metodi di estensione che è possibile concatenare per configurare le opzioni di protezione dei dati.

Nota

Questo articolo è stato scritto per un'app eseguita all'interno di un contenitore Docker. In un contenitore Docker, l'app ha sempre lo stesso percorso e, di conseguenza, lo stesso discriminante dell'applicazione. Le app che devono essere eseguite in più ambienti ,ad esempio locali e distribuite, devono impostare il discriminatorio dell'applicazione predefinito per l'ambiente. L'esecuzione di un'app in più ambienti non rientra nell'ambito di questo articolo.

I pacchetti NuGet seguenti sono necessari per le estensioni di protezione dei dati usate in questo articolo:

Proteggere le chiavi con Azure Key Vault (ProtectKeysWithAzureKeyVault)

Per interagire con Azure Key Vault in locale usando le credenziali dello sviluppatore, accedere all'account di archiviazione in Visual Studio o accedere con l'interfaccia della riga di comando di Azure. Se l'interfaccia della riga di comando di Azure non è già stata installata, vedere Come installare l'interfaccia della riga di comando di Azure. È possibile eseguire il comando seguente nel pannello Developer PowerShell in Visual Studio o da una shell dei comandi quando non si usa Visual Studio:

az login

Per altre informazioni, vedere Accedere ad Azure usando gli strumenti per sviluppatori.

Quando si configura il vault delle chiavi nel portale Entra o Azure:

  • Configurare il Key Vault per utilizzare l'accesso basato sui ruoli di Azure. Se non si utilizza una rete virtuale di Azure, anche per sviluppo e test locali, assicurarsi che l'accesso pubblico nella sezione Rete sia abilitato (selezionato). L'abilitazione dell'accesso pubblico espone solo l'endpoint del Key Vault. Gli account autenticati sono ancora necessari per l'accesso.

  • Creare un'istanza gestita di Identity Azure (o aggiungere un ruolo all'istanza gestita Identity esistente che si prevede di usare) con il ruolo Crypto User di Key Vault . Assegna il gestito Identity al Servizio App di Azure che ospita la distribuzione: Impostazioni>Identity>Assegnato dall'utente>Aggiungi.

    Nota

    Se hai intenzione di eseguire un'app in locale con un utente autorizzato per l'accesso ai blob utilizzando l'interfaccia della riga di comando di Azure o l'autenticazione dei servizi Azure di Visual Studio, aggiungi il tuo account utente sviluppatore di Azure in Controllo di accesso (IAM) con il ruolo di Key Vault Crypto User. Se si vuole usare l'interfaccia della riga di comando di Azure tramite Visual Studio, eseguire il az login comando dal pannello Developer PowerShell e seguire le istruzioni per l'autenticazione con il tenant.

  • Quando la crittografia della chiave è attiva, le chiavi nel file delle chiavi includono il commento "This key is encrypted with Azure Key Vault.". Dopo aver avviato l'app, selezionare il comando Visualizza/modifica dal menu di scelta rapida alla fine della riga della chiave per verificare che una chiave sia presente con la sicurezza del key vault applicata.

  • Facoltativamente, è possibile abilitare la rotazione automatica delle chiavi del Key Vault senza doversi preoccupare di decrittografare i payload con chiavi di protezione dati basate su chiavi del Key Vault scadute o ruotate. Ogni chiave di protezione dei dati generata include un riferimento alla chiave del Key Vault utilizzata per crittografarla. Assicurati di non eliminare le chiavi scadute nell'insieme di chiavi, ma di conservarle. Usare un identificatore di chiave senza versione nella configurazione del vault delle chiavi dell'app, senza un GUID della chiave alla fine dell'identificatore (ad esempio: https://contoso.vault.azure.net/keys/data-protection). Usare un periodo di rotazione simile per entrambe le chiavi, con la chiave del key vault che ruota più frequentemente rispetto alla chiave di protezione dei dati, per assicurarsi che venga utilizzata una nuova chiave del key vault al momento della rotazione della chiave di protezione dei dati.

La protezione delle chiavi con Azure Key Vault implementa un oggetto IXmlEncryptor che disabilita le impostazioni di protezione automatica dei dati, inclusa la posizione di archiviazione dell'anello delle chiavi. Per configurare il provider di Archiviazione BLOB di Azure per archiviare le chiavi nell'archiviazione BLOB, seguire le indicazioni in Provider di archiviazione chiavi in ASP.NET Core e chiamare uno degli PersistKeysToAzureBlobStorage overload nell'app. L'esempio seguente utilizza l'overload che accetta un URI blob e le credenziali del token (TokenCredential), facendo affidamento su un servizio gestito Identity di Azure per il controllo degli accessi basato sui ruoli (RBAC).

Per configurare il provider di Azure Key Vault, usa uno dei sovraccarichi ProtectKeysWithAzureKeyVault. Nell'esempio seguente viene utilizzato l'overload che accetta l'identificatore della chiave e le credenziali del token (TokenCredential), basandosi su un Managed Identity per il controllo degli accessi in base al ruolo in produzione (ManagedIdentityCredential) o durante lo sviluppo e i test DefaultAzureCredential. Altri sovraccarichi accettano un client delle chiavi o un ID client dell'app con segreto del client. Per altre informazioni, vedere Provider di archiviazione chiavi in ASP.NET Core.

Per altre informazioni sull'API e sull'autenticazione di Azure SDK, vedere Autenticare le app .NET nei servizi di Azure usando la libreria di Azure Identity e Fornire l'accesso a chiavi, certificati e segreti di Key Vault con il controllo degli accessi in base al ruolo di Azure. Per indicazioni sulla registrazione, vedere Registrazione con Azure SDK per .NET: Registrazione senza registrazione client. Per le app che usano l'inserimento delle dipendenze, un'app può chiamare AddAzureClientsCore, passando true per enableLogForwarding, per creare e collegare l'infrastruttura di log.

Program Nel file in cui sono registrati i servizi:

TokenCredential? credential;

if (builder.Environment.IsProduction())
{
    credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
    // Local development and testing only
    DefaultAzureCredentialOptions options = new()
    {
        // Specify the tenant ID to use the dev credentials when running the app locally
        // in Visual Studio.
        VisualStudioTenantId = "{TENANT ID}",
        SharedTokenCacheTenantId = "{TENANT ID}"
    };

    credential = new DefaultAzureCredential(options);
}

builder.Services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

{MANAGED IDENTITY CLIENT ID}: ID client gestito di Azure Identity (GUID).

{TENANT ID}: ID locatario.

{APPLICATION NAME}: SetApplicationName imposta il nome univoco dell'app all'interno del sistema di protezione dei dati. Il valore deve corrispondere tra le distribuzioni dell'app.

{BLOB URI}: URI completo del file di chiave. L'URI è generato da Azure Storage quando si crea il file della chiave. Non usare un SAS.

{KEY IDENTIFIER}: identificatore di chiave di Azure Key Vault usato per la crittografia delle chiavi. Un criterio di accesso consente all'applicazione di accedere all'archivio delle chiavi con le autorizzazioni Get, Unwrap Key e Wrap Key. La versione della chiave viene ottenuta dalla chiave nel portale Entra o nel portale Azure dopo che è stata creata. Se si abilita la rotazione automatica della chiave nel Key Vault, assicurarsi di utilizzare un identificatore di chiave senza versione nella configurazione del Key Vault dell'app, senza inserire alcun GUID della chiave alla fine dell'identificatore (ad esempio: https://contoso.vault.azure.net/keys/data-protection).

Per consentire a un'app di comunicare e autorizzarsi con Azure Key Vault, è necessario fare riferimento al Azure.Identity pacchetto NuGet dall'app.

Nota

Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Verificare le versioni corrette dei pacchetti in NuGet.org.

Nota

Negli ambienti non di produzione, l'esempio precedente usa DefaultAzureCredential per semplificare l'autenticazione durante lo sviluppo di app distribuite in Azure combinando le credenziali usate negli ambienti di hosting di Azure con le credenziali usate nello sviluppo locale. Per altre informazioni, vedere Autenticare le app .NET ospitate in Azure nelle risorse di Azure usando un'identità gestita assegnata dal sistema.

Se l'app usa i pacchetti di Azure precedenti (Microsoft.AspNetCore.DataProtection.AzureStorage e Microsoft.AspNetCore.DataProtection.AzureKeyVault), è consigliabile rimuovere questi riferimenti e eseguire l'aggiornamento ai Azure.Extensions.AspNetCore.DataProtection.Blobs pacchetti e Azure.Extensions.AspNetCore.DataProtection.Keys . I pacchetti più recenti risondono problemi di sicurezza e stabilità principali.

Approccio alternativo alla firma di accesso condiviso (SAS): in alternativa all'uso di un'istanza gestita Identity per l'accesso al key blob in Azure Blob Storage, è possibile chiamare l'overload PersistKeysToAzureBlobStorage che accetta un URI BLOB con un token SAS. L'esempio seguente continua a usare un ManagedIdentityCredential (produzione) o un DefaultAzureCredential (sviluppo e test) per il loro TokenCredential, come illustrato nell'esempio precedente.

builder.Services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

{APPLICATION NAME}: SetApplicationName imposta il nome univoco dell'app all'interno del sistema di protezione dei dati. Il valore deve corrispondere tra le distribuzioni dell'app.

{BLOB URI WITH SAS}: URI completo in cui deve essere archiviato il file di chiave con il token di firma di accesso condiviso come parametro della stringa di query. L'URI viene generato da Archiviazione di Azure quando si richiede una firma di accesso condiviso per il file di chiave caricato.

{KEY IDENTIFIER}: identificatore di chiave di Azure Key Vault usato per la crittografia delle chiavi. Un criterio di accesso consente all'applicazione di accedere all'archivio delle chiavi con le autorizzazioni Get, Unwrap Key e Wrap Key. La versione della chiave viene ottenuta dalla chiave nel portale Entra o nel portale Azure dopo che è stata creata. Se si abilita la rotazione automatica della chiave nel Key Vault, assicurarsi di utilizzare un identificatore di chiave senza versione nella configurazione del Key Vault dell'app, senza inserire alcun GUID della chiave alla fine dell'identificatore (ad esempio: https://contoso.vault.azure.net/keys/data-protection).

Rendere persistenti le chiavi nel file system (PersistKeysToFileSystem)

Per archiviare le chiavi in una condivisione UNC anziché nel percorso predefinito %LOCALAPPDATA% , configurare il sistema con PersistKeysToFileSystem:

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

Avviso

Se si modifica il percorso di persistenza della chiave, il sistema non crittografa più automaticamente le chiavi inattive, perché non sa se DPAPI è un meccanismo di crittografia appropriato.

Rendere persistenti le chiavi in un database (PersistKeysToDbContext)

Per archiviare le chiavi in un database usando EntityFramework, configurare il sistema con il pacchetto Microsoft.AspNetCore.DataProtection.EntityFrameworkCore :

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

Il codice precedente archivia le chiavi nel database configurato. Il contesto del database utilizzato deve implementare IDataProtectionKeyContext. IDataProtectionKeyContext espone la proprietà DataProtectionKeys

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

Questa proprietà rappresenta la tabella in cui vengono archiviate le chiavi. Creare la tabella manualmente o con DbContext Migrazioni. Per ulteriori informazioni, vedere DataProtectionKey.

API di configurazione delle chiavi di protezione (ProtectKeysWith\*)

È possibile configurare il sistema per proteggere le chiavi a riposo chiamando una delle API di configurazione di ProtectKeysWith\*. Si consideri l'esempio seguente, che archivia le chiavi in una condivisione UNC e crittografa tali chiavi inattive con un certificato X.509 specifico.

È possibile fornire un oggetto X509Certificate2 a ProtectKeysWithCertificate da un file chiamando X509CertificateLoader.LoadCertificateFromFile:

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

L'esempio di codice seguente illustra come caricare un certificato usando un'identificazione personale:

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

È possibile fornire un oggetto X509Certificate2 a ProtectKeysWithCertificate, ad esempio un certificato caricato da un file:

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

L'esempio di codice seguente illustra come caricare un certificato usando un'identificazione personale:

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

Per esempi e discussioni sui meccanismi di crittografia delle chiavi predefiniti, vedere Crittografia delle chiavi inattivi in Windows e Azure con ASP.NET Core.

Rimuovere la protezione delle chiavi con qualsiasi certificato (UnprotectKeysWithAnyCertificate)

È possibile ruotare i certificati e decrittografare le chiavi inattive usando una matrice di certificati X509Certificate2 con UnprotectKeysWithAnyCertificate:

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"]));

Impostare la durata della chiave predefinita (SetDefaultKeyLifetime)

Per configurare il sistema per l'uso di una durata chiave di 14 giorni anziché di 90 giorni predefiniti, usare SetDefaultKeyLifetime:

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

Impostare il nome dell'applicazione (SetApplicationName)

Per impostazione predefinita, il sistema di protezione dei dati isola le app l'una dall'altra in base ai percorsi radice del contenuto, anche se condividono lo stesso repository di chiavi fisiche. Questo isolamento impedisce alle app di comprendere i payload protetti tra loro.

Per condividere payload protetti tra le app:

  • Configura SetApplicationName in ogni app con lo stesso valore.
  • Usare la stessa versione dello stack di API Protezione dati tra le app. Eseguire una delle operazioni seguenti nei file di progetto delle app:
    • Fare riferimento alla stessa versione del framework condiviso tramite il metapacchetto Microsoft.AspNetCore.App.
    • Fare riferimento alla stessa versione del pacchetto di protezione dei dati.
builder.Services.AddDataProtection()
    .SetApplicationName("<sharedApplicationName>");

SetApplicationName internamente imposta DataProtectionOptions.ApplicationDiscriminator. Ai fini della risoluzione dei problemi, il valore assegnato al discriminatorio dal framework può essere registrato con il codice seguente inserito dopo la WebApplication compilazione di Program.cs:

var discriminator = app.Services.GetRequiredService<IOptions<DataProtectionOptions>>()
    .Value.ApplicationDiscriminator;
app.Logger.LogInformation("ApplicationDiscriminator: {ApplicationDiscriminator}", discriminator);

Per ulteriori informazioni su come viene utilizzato il discriminatore, vedere le sezioni seguenti in questo articolo:

Avviso

In .NET 6 WebApplicationBuilder normalizza il percorso radice del contenuto per terminare con un oggetto DirectorySeparatorChar. Ad esempio, su Windows il percorso radice del contenuto termina in \ e su Linux in /. Gli altri host non normalizzano il percorso. La maggior parte delle app che eseguono la migrazione da HostBuilder o WebHostBuilder non condividerà lo stesso nome dell'app perché non avrà la terminazione DirectorySeparatorChar. Per risolvere questo problema, rimuovere il carattere separatore di directory e impostare manualmente il nome dell'app, come illustrato nel codice seguente:

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

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();

Disabilitare la generazione automatica delle chiavi (DisableAutomaticKeyGeneration)

Si potrebbe avere uno scenario in cui non si vuole che un'app rollback automatico delle chiavi (creare nuove chiavi) man mano che si avvicinano alla scadenza. Un esempio di questo scenario potrebbe essere costituito dalle app configurate in una relazione primaria/secondaria, in cui solo l'app primaria è responsabile dei problemi di gestione delle chiavi e le app secondarie hanno semplicemente una visualizzazione di sola lettura dell'anello chiave. Le app secondarie possono essere configurate per considerare l'anello di chiave come di sola lettura configurando il sistema con DisableAutomaticKeyGeneration:

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

Isolamento per singola applicazione

Quando il sistema di protezione dei dati viene fornito da un host ASP.NET Core, isola automaticamente le app l'una dall'altra, anche se tali app vengono eseguite con lo stesso account del processo di lavoro e usano lo stesso materiale di master keying. È simile al modificatore IsolateApps dall'elemento system.Web <machineKey> .

Il meccanismo di isolamento funziona trattando ciascuna app sul computer locale come un tenant univoco, perciò la radice IDataProtector di qualsiasi app specifica include automaticamente l'ID dell'app come discriminante (ApplicationDiscriminator). L'ID univoco dell'app è il percorso fisico dell'app:

  • Per le app ospitate in IIS, l'ID univoco è il percorso fisico IIS dell'app. Se un'app viene distribuita in un ambiente web farm, questo valore è stabile presupponendo che gli ambienti IIS siano configurati in modo analogo in tutti i computer della Web farm.
  • Per le app self-hosted in esecuzione nel Kestrel server, l'ID univoco è il percorso fisico dell'app su disco.

L'identificatore univoco è progettato per sopravvivere alle reimpostazioni, sia della singola app che del computer stesso.

Questo meccanismo di isolamento presuppone che le app non siano dannose. Un'app dannosa può sempre influire su qualsiasi altra app in esecuzione con lo stesso account del processo di lavoro. In un ambiente di hosting condiviso in cui le app non sono attendibili a vicenda, il provider di hosting deve adottare misure per garantire l'isolamento a livello di sistema operativo tra le app, inclusa la separazione dei repository delle chiavi sottostanti delle app.

Se il sistema di protezione dati non viene fornito da un host ASP.NET Core (ad esempio, se si crea un'istanza tramite il tipo concreto DataProtectionProvider), l'isolamento dell'app è disabilitato per impostazione predefinita. Quando l'isolamento dell'app è disabilitato, tutte le app supportate dallo stesso materiale di keying possono condividere i payload purché forniscano gli scopi appropriati. Per fornire l'isolamento dell'app in questo ambiente, chiamare il SetApplicationName metodo sull'oggetto di configurazione e specificare un nome univoco per ogni app.

Protezione dei dati e isolamento delle app

Considerare i punti seguenti per l'isolamento delle app:

  • Quando più app puntano allo stesso repository di chiavi, l'intenzione è che le app condividano lo stesso materiale della chiave master. La protezione dei dati viene sviluppata presupponendo che tutte le app che condividono un anello di chiave possano accedere a tutti gli elementi dell'anello di chiave. L'identificatore univoco dell'applicazione viene usato per isolare le chiavi specifiche dell'applicazione derivate dalle chiavi fornite dall'anello di chiave. Non prevede autorizzazioni a livello di elemento, ad esempio quelle fornite da Azure KeyVault per applicare l'isolamento aggiuntivo. Il tentativo di autorizzazioni a livello di elemento genera errori dell'applicazione. Se non si vuole basarsi sull'isolamento predefinito dell'applicazione, è consigliabile usare posizioni separate dell'archivio chiavi e non condividere tra le applicazioni.

  • Il discriminante dell'applicazione (ApplicationDiscriminator) viene usato per consentire alle app diverse di condividere lo stesso materiale della chiave master, ma di mantenere i payload crittografici distinti l'uno dall'altro. Affinché le app possano leggere i payload crittografici degli altri, devono avere lo stesso discriminante dell'applicazione, che può essere impostato chiamando SetApplicationName.

  • Se un'app viene compromessa (ad esempio, da un attacco RCE), tutto il materiale della chiave master accessibile a tale app deve essere considerato compromesso, indipendentemente dal relativo stato di protezione inattivo. Ciò implica che se due app puntano allo stesso repository, anche se usano diversi discriminatori di app, un compromesso di uno è funzionalmente equivalente a un compromesso di entrambi.

    Questa clausola "funzionalmente equivalente a una compromissione di entrambe" rimane valida anche se le due app usano meccanismi diversi per la protezione delle chiavi a riposo. In genere, questa non è una configurazione prevista. Il meccanismo di protezione dei dati inattivi è progettato per fornire protezione nel caso in cui un eventuale attaccante informatico ottenga l'accesso in lettura al repository. Un cyberattacker che ottiene l'accesso in scrittura al repository (forse perché ha ottenuto l'autorizzazione di esecuzione del codice all'interno di un'app) può inserire chiavi dannose nella risorsa di archiviazione. Il sistema di protezione dei dati non fornisce intenzionalmente protezione da un cyberattacker che ottiene l'accesso in scrittura al repository delle chiavi.

  • Se le app devono rimanere veramente isolate l'una dall'altra, devono usare repository di chiavi diversi. Ciò non rientra naturalmente nella definizione di "isolato". Le app non sono isolate se hanno accesso in lettura e scrittura agli archivi dati delle altre.

Modifica degli algoritmi con UseCryptographicAlgorithms

Lo stack di protezione dati consente di modificare l'algoritmo predefinito usato dalle chiavi appena generate. Il modo più semplice per eseguire questa operazione consiste nel chiamare UseCryptographicAlgorithms dal callback di configurazione:

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

Il valore predefinito di EncryptionAlgorithm è AES-256-CBC e il valore predefinito ValidationAlgorithm è HMACSHA256. I criteri predefiniti possono essere impostati da un amministratore di sistema tramite un criterio valido per tutta la macchina, ma una chiamata esplicita per esegue l'override dei criteri predefiniti.

La chiamata UseCryptographicAlgorithms consente di specificare l'algoritmo desiderato da un elenco predefinito. Non è necessario preoccuparsi dell'implementazione dell'algoritmo. Nello scenario precedente, il sistema di protezione dei dati tenta di usare l'implementazione CNG di AES se in esecuzione in Windows. In caso contrario, effettua un fallback alla classe gestita System.Security.Cryptography.Aes.

È possibile specificare manualmente un'implementazione tramite una chiamata a UseCustomCryptographicAlgorithms.

Suggerimento

La modifica degli algoritmi non influisce sulle chiavi esistenti nell'anello di tasti. Influisce solo sulle chiavi appena generate.

Specificare algoritmi personalizzati gestiti

Per specificare algoritmi gestiti personalizzati, creare un'istanza ManagedAuthenticatedEncryptorConfiguration che punti ai tipi di implementazione:

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)
    });

In genere, le proprietà *Type devono puntare a implementazioni concrete e istanziabili (tramite un costruttore pubblico senza parametri) di SymmetricAlgorithm e KeyedHashAlgorithm, sebbene il sistema gestisca in modo speciale alcuni valori come typeof(Aes) per praticità.

Nota

SymmetricAlgorithm deve avere una lunghezza della chiave di ≥ 128 bit e una dimensione del blocco di ≥ 64 bit e deve supportare la crittografia in modalità CBC con spaziatura interna PKCS #7. KeyedHashAlgorithm deve avere una dimensione digest pari >a = 128 bit e deve supportare chiavi di lunghezza uguale alla lunghezza del digest dell'algoritmo hash. Non è strettamente necessario che KeyedHashAlgorithm sia HMAC.

Specificare algoritmi personalizzati di Windows CNG

Per specificare un algoritmo CNG di Windows personalizzato usando la crittografia in modalità CBC con convalida HMAC, creare un'istanza CngCbcAuthenticatedEncryptorConfiguration contenente le informazioni algoritmiche:

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
    });

Nota

L'algoritmo di crittografia a blocchi simmetrici deve avere una lunghezza della >chiave = 128 bit, una dimensione del blocco = >64 bit e deve supportare la crittografia in modalità CBC con spaziatura interna PKCS #7. L'algoritmo hash deve avere una dimensione del digest = >128 bit e deve supportare l'apertura con il flag BCRYPT_ALG_HANDLE_HMAC_FLAG. Le proprietà *Provider possono essere impostate su null per usare il provider predefinito per l'algoritmo specificato. Per altre informazioni, vedere la documentazione di BCryptOpenAlgorithmProvider .

Per specificare un algoritmo CNG di Windows personalizzato usando la crittografia galois/modalità contatore con la convalida, creare un'istanza CngGcmAuthenticatedEncryptorConfiguration contenente le informazioni algoritmiche:

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

        // Specified in bits
        EncryptionAlgorithmKeySize = 256
    });

Nota

L'algoritmo di crittografia a blocchi simmetrici deve avere una lunghezza della >chiave = 128 bit, una dimensione del blocco di esattamente 128 bit e deve supportare la crittografia GCM. È possibile impostare la EncryptionAlgorithmProvider proprietà su Null per utilizzare il provider predefinito per l'algoritmo specificato. Per altre informazioni, vedere la documentazione di BCryptOpenAlgorithmProvider .

Specifica di altri algoritmi personalizzati

Anche se non esposto come API di prima classe, il sistema di protezione dei dati è sufficientemente estensibile per consentire di specificare quasi qualsiasi tipo di algoritmo. Ad esempio, è possibile mantenere tutte le chiavi contenute in un modulo HSM (Hardware Security Module) e fornire un'implementazione personalizzata delle routine di crittografia e decrittografia principali. Per altre informazioni, vedere l'articolo IAuthenticatedEncryptor relativo all'estendibilità della crittografia core.

Permanenza delle chiavi durante l'hosting in un container Docker

Quando si ospita in un contenitore Docker , le chiavi devono essere mantenute in uno dei due casi seguenti:

Persistenza delle chiavi con Redis

Per archiviare le chiavi è necessario usare solo le versioni redis che supportano la persistenza dei dati Redis. L'archiviazione BLOB di Azure è persistente e può essere usata per archiviare le chiavi. Per altre informazioni, vedere questo problema in GitHub.

Registrazione

Abilita il livello di registrazione Information o inferiore per diagnosticare problemi. Il file seguente appsettings.json abilita la registrazione delle informazioni dell'API protezione dati:

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

Per altre informazioni sulla registrazione, vedere Registrazione in .NET Core e ASP.NET Core.

Risorse aggiuntive

Quando il sistema di protezione dati viene inizializzato, applica le impostazioni predefinite in base all'ambiente operativo. Queste impostazioni sono appropriate per le app in esecuzione in un singolo computer. Tuttavia, esistono casi in cui uno sviluppatore può voler modificare le impostazioni predefinite:

  • L'app viene distribuita in più computer.
  • Per motivi di conformità.

Per questi scenari, il sistema di protezione dei dati offre un'API di configurazione avanzata.

Avviso

Analogamente ai file di configurazione, l'anello della chiave di protezione dei dati deve essere protetto usando le autorizzazioni appropriate. È possibile scegliere di crittografare le chiavi inattive, ma ciò non impedisce ai cyberattacker di creare nuove chiavi. Di conseguenza, la sicurezza dell'app è interessata. Il percorso di archiviazione configurato con Protezione dati deve avere accesso limitato all'app stessa, in modo analogo al modo in cui si proteggerebbero i file di configurazione. Ad esempio, se si sceglie di archiviare l'anello di chiave su disco, usare le autorizzazioni del file system. Assicurati che solo l'identità con cui viene eseguita l'app web abbia accesso in lettura e scrittura a tale directory. Se si usa Azure Blob Storage, solo l'app Web dovrebbe essere l'unica a poter leggere, scrivere o creare nuove voci nell'archivio BLOB.

Il metodo di estensione AddDataProtection restituisce un oggetto IDataProtectionBuilder, che espone metodi di estensione che possono essere concatenati per configurare le opzioni di protezione dei dati.

I pacchetti NuGet seguenti sono necessari per le estensioni di protezione dei dati usate in questo articolo:

Nota

Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Verificare le versioni corrette dei pacchetti in NuGet.org.

Proteggere le chiavi con Azure Key Vault (ProtectKeysWithAzureKeyVault)

Per interagire con Azure Key Vault in locale usando le credenziali dello sviluppatore, accedere all'account di archiviazione in Visual Studio o accedere con l'interfaccia della riga di comando di Azure. Se l'interfaccia della riga di comando di Azure non è già stata installata, vedere Come installare l'interfaccia della riga di comando di Azure. È possibile eseguire il comando seguente nel pannello Developer PowerShell in Visual Studio o da una shell dei comandi quando non si usa Visual Studio:

az login

Per altre informazioni, vedere Accedere ad Azure usando gli strumenti per sviluppatori.

Quando si configura il vault delle chiavi nel portale Entra o Azure:

  • Configurare il Key Vault per utilizzare l'accesso basato sui ruoli di Azure. Se non si utilizza una rete virtuale di Azure, anche per sviluppo e test locali, assicurarsi che l'accesso pubblico nella sezione Rete sia abilitato (selezionato). L'abilitazione dell'accesso pubblico espone solo l'endpoint del Key Vault. Gli account autenticati sono ancora necessari per l'accesso.

  • Creare un'istanza gestita di Identity Azure (o aggiungere un ruolo all'istanza gestita Identity esistente che si prevede di usare) con il ruolo Crypto User di Key Vault . Assegna il gestito Identity al Servizio App di Azure che ospita la distribuzione: Impostazioni>Identity>Assegnato dall'utente>Aggiungi.

    Nota

    Se hai intenzione di eseguire un'app in locale con un utente autorizzato per l'accesso ai blob utilizzando l'interfaccia della riga di comando di Azure o l'autenticazione dei servizi Azure di Visual Studio, aggiungi il tuo account utente sviluppatore di Azure in Controllo di accesso (IAM) con il ruolo di Key Vault Crypto User. Se si vuole usare l'interfaccia della riga di comando di Azure tramite Visual Studio, eseguire il az login comando dal pannello Developer PowerShell e seguire le istruzioni per l'autenticazione con il tenant.

  • Quando la crittografia della chiave è attiva, le chiavi nel file delle chiavi includono il commento "This key is encrypted with Azure Key Vault.". Dopo aver avviato l'app, selezionare il comando Visualizza/modifica dal menu di scelta rapida alla fine della riga della chiave per verificare che una chiave sia presente con la sicurezza del key vault applicata.

  • Facoltativamente, è possibile abilitare la rotazione automatica delle chiavi del Key Vault senza doversi preoccupare di decrittografare i payload con chiavi di protezione dati basate su chiavi del Key Vault scadute o ruotate. Ogni chiave di protezione dei dati generata include un riferimento alla chiave del Key Vault utilizzata per crittografarla. Assicurati di non eliminare le chiavi scadute nell'insieme di chiavi, ma di conservarle. Usare un identificatore di chiave senza versione nella configurazione del vault delle chiavi dell'app, senza un GUID della chiave alla fine dell'identificatore (ad esempio: https://contoso.vault.azure.net/keys/data-protection). Usare un periodo di rotazione simile per entrambe le chiavi, con la chiave del key vault che ruota più frequentemente rispetto alla chiave di protezione dei dati, per assicurarsi che venga utilizzata una nuova chiave del key vault al momento della rotazione della chiave di protezione dei dati.

La protezione delle chiavi con Azure Key Vault implementa un oggetto IXmlEncryptor che disabilita le impostazioni di protezione automatica dei dati, inclusa la posizione di archiviazione dell'anello delle chiavi. Per configurare il provider di Archiviazione BLOB di Azure per archiviare le chiavi nell'archiviazione BLOB, seguire le indicazioni in Provider di archiviazione chiavi in ASP.NET Core e chiamare uno degli PersistKeysToAzureBlobStorage overload nell'app. L'esempio seguente utilizza l'overload che accetta un URI blob e le credenziali del token (TokenCredential), facendo affidamento su un servizio gestito Identity di Azure per il controllo degli accessi basato sui ruoli (RBAC).

Per configurare il provider di Azure Key Vault, usa uno dei sovraccarichi ProtectKeysWithAzureKeyVault. Nell'esempio seguente viene utilizzato l'overload che accetta l'identificatore della chiave e le credenziali del token (TokenCredential), basandosi su un Managed Identity per il controllo degli accessi in base al ruolo in produzione (ManagedIdentityCredential) o durante lo sviluppo e i test DefaultAzureCredential. Altri sovraccarichi accettano un client delle chiavi o un ID client dell'app con segreto del client. Per altre informazioni, vedere Provider di archiviazione chiavi in ASP.NET Core.

Per altre informazioni sull'API e sull'autenticazione di Azure SDK, vedere Autenticare le app .NET nei servizi di Azure usando la libreria di Azure Identity e Fornire l'accesso a chiavi, certificati e segreti di Key Vault con il controllo degli accessi in base al ruolo di Azure. Per indicazioni sulla registrazione, vedere Registrazione con Azure SDK per .NET: Registrazione senza registrazione client. Per le app che usano l'inserimento delle dipendenze, un'app può chiamare AddAzureClientsCore, passando true per enableLogForwarding, per creare e collegare l'infrastruttura di log.

Program Nel file in cui sono registrati i servizi:

TokenCredential? credential;

if (builder.Environment.IsProduction())
{
    credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
    // Local development and testing only
    DefaultAzureCredentialOptions options = new()
    {
        // Specify the tenant ID to use the dev credentials when running the app locally
        // in Visual Studio.
        VisualStudioTenantId = "{TENANT ID}",
        SharedTokenCacheTenantId = "{TENANT ID}"
    };

    credential = new DefaultAzureCredential(options);
}

services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

{MANAGED IDENTITY CLIENT ID}: ID client gestito di Azure Identity (GUID).

{TENANT ID}: ID del tenant.

{APPLICATION NAME}: SetApplicationName imposta il nome univoco dell'app all'interno del sistema di protezione dei dati. Il valore deve corrispondere tra le distribuzioni dell'app.

{BLOB URI}: URI completo del file di chiave. L'URI è generato da Azure Storage quando si crea il file della chiave. Non usare un SAS.

{KEY IDENTIFIER}: identificatore di chiave di Azure Key Vault usato per la crittografia delle chiavi. Un criterio di accesso consente all'applicazione di accedere all'archivio delle chiavi con le autorizzazioni Get, Unwrap Key e Wrap Key. La versione della chiave viene ottenuta dalla chiave nel portale Entra o nel portale Azure dopo che è stata creata. Se si abilita la rotazione automatica della chiave nel Key Vault, assicurarsi di utilizzare un identificatore di chiave senza versione nella configurazione del Key Vault dell'app, senza inserire alcun GUID della chiave alla fine dell'identificatore (ad esempio: https://contoso.vault.azure.net/keys/data-protection).

Per consentire a un'app di comunicare e autorizzarsi con Azure Key Vault, è necessario fare riferimento al Azure.Identity pacchetto NuGet dall'app.

Nota

Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Verificare le versioni corrette dei pacchetti in NuGet.org.

Nota

Negli ambienti non di produzione, l'esempio precedente usa DefaultAzureCredential per semplificare l'autenticazione durante lo sviluppo di app distribuite in Azure combinando le credenziali usate negli ambienti di hosting di Azure con le credenziali usate nello sviluppo locale. Per altre informazioni, vedere Autenticare le app .NET ospitate in Azure nelle risorse di Azure usando un'identità gestita assegnata dal sistema.

Se l'app usa i pacchetti di Azure precedenti (Microsoft.AspNetCore.DataProtection.AzureStorage e Microsoft.AspNetCore.DataProtection.AzureKeyVault), è consigliabile rimuovere questi riferimenti e eseguire l'aggiornamento ai Azure.Extensions.AspNetCore.DataProtection.Blobs pacchetti e Azure.Extensions.AspNetCore.DataProtection.Keys . I pacchetti più recenti risondono problemi di sicurezza e stabilità principali.

Approccio alternativo alla firma di accesso condiviso (SAS): in alternativa all'uso di un'istanza gestita Identity per l'accesso al key blob in Azure Blob Storage, è possibile chiamare l'overload PersistKeysToAzureBlobStorage che accetta un URI BLOB con un token SAS. L'esempio seguente continua a usare un ManagedIdentityCredential (produzione) o un DefaultAzureCredential (sviluppo e test) per il loro TokenCredential, come illustrato nell'esempio precedente.

services.AddDataProtection()
    .SetApplicationName("{APPLICATION NAME}")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

{APPLICATION NAME}: SetApplicationName imposta il nome univoco dell'app all'interno del sistema di protezione dei dati. Il valore deve corrispondere tra le distribuzioni dell'app.

{BLOB URI WITH SAS}: URI completo in cui deve essere archiviato il file di chiave con il token di firma di accesso condiviso come parametro della stringa di query. L'URI viene generato da Archiviazione di Azure quando si richiede una firma di accesso condiviso per il file di chiave caricato.

{KEY IDENTIFIER}: identificatore di chiave di Azure Key Vault usato per la crittografia delle chiavi. Un criterio di accesso consente all'applicazione di accedere all'archivio delle chiavi con le autorizzazioni Get, Unwrap Key e Wrap Key. La versione della chiave viene ottenuta dalla chiave nel portale Entra o nel portale Azure dopo che è stata creata. Se si abilita la rotazione automatica della chiave nel Key Vault, assicurarsi di utilizzare un identificatore di chiave senza versione nella configurazione del Key Vault dell'app, senza inserire alcun GUID della chiave alla fine dell'identificatore (ad esempio: https://contoso.vault.azure.net/keys/data-protection).

Rendere persistenti le chiavi nel file system (PersistKeysToFileSystem)

Per archiviare le chiavi in una condivisione UNC anziché nel percorso predefinito %LOCALAPPDATA% , configurare il sistema con PersistKeysToFileSystem:

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

Avviso

Se si modifica il percorso di persistenza della chiave, il sistema non crittografa più automaticamente le chiavi inattive, perché non sa se DPAPI è un meccanismo di crittografia appropriato.

Rendere persistenti le chiavi in un database (PersistKeysToDbContext)

Per archiviare le chiavi in un database usando EntityFramework, configurare il sistema con il pacchetto Microsoft.AspNetCore.DataProtection.EntityFrameworkCore :

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

Il codice precedente archivia le chiavi nel database configurato. Il contesto del database utilizzato deve implementare IDataProtectionKeyContext. IDataProtectionKeyContext espone la proprietà DataProtectionKeys

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

Questa proprietà rappresenta la tabella in cui vengono archiviate le chiavi. Creare la tabella manualmente o con DbContext Migrazioni. Per ulteriori informazioni, vedere DataProtectionKey.

API di configurazione delle chiavi di protezione (ProtectKeysWith\*)

È possibile configurare il sistema per proteggere le chiavi a riposo chiamando una delle API di configurazione di ProtectKeysWith\*. Si consideri l'esempio seguente, che archivia le chiavi in una condivisione UNC e crittografa tali chiavi inattive con un certificato X.509 specifico:

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

È possibile fornire un oggetto X509Certificate2 a ProtectKeysWithCertificate, ad esempio un certificato caricato da un file:

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

Per altri esempi e discussione sui meccanismi di crittografia delle chiavi predefiniti, vedere Crittografia delle chiavi inattivi in Windows e Azure con ASP.NET Core.

Rimuovere la protezione delle chiavi con qualsiasi certificato (UnprotectKeysWithAnyCertificate)

È possibile ruotare i certificati e decrittografare le chiavi inattive usando una matrice di certificati X509Certificate2 con UnprotectKeysWithAnyCertificate:

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"]));
}

Impostare la durata della chiave predefinita (SetDefaultKeyLifetime)

Per configurare il sistema per l'uso di una durata chiave di 14 giorni anziché di 90 giorni predefiniti, usare SetDefaultKeyLifetime:

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

Impostare il nome dell'applicazione (SetApplicationName)

Per impostazione predefinita, il sistema di protezione dei dati isola le app l'una dall'altra in base ai percorsi radice del contenuto, anche se condividono lo stesso repository di chiavi fisiche. Questo isolamento impedisce alle app di comprendere i payload protetti tra loro.

Per condividere payload protetti tra le app:

  • Configura SetApplicationName in ogni app con lo stesso valore.
  • Usare la stessa versione dello stack di API Protezione dati tra le app. Eseguire una delle operazioni seguenti nei file di progetto delle app:
    • Fare riferimento alla stessa versione del framework condiviso tramite il metapacchetto Microsoft.AspNetCore.App.
    • Fare riferimento alla stessa versione del pacchetto di protezione dei dati.
public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .SetApplicationName("{APPLICATION NAME}");
}

SetApplicationName internamente imposta DataProtectionOptions.ApplicationDiscriminator. Per ulteriori informazioni su come viene utilizzato il discriminatore, vedere le sezioni seguenti in questo articolo:

Disabilitare la generazione automatica delle chiavi (DisableAutomaticKeyGeneration)

Si potrebbe avere uno scenario in cui non si vuole che un'app rollback automatico delle chiavi (creare nuove chiavi) man mano che si avvicinano alla scadenza. Un esempio di questo scenario potrebbe essere costituito dalle app configurate in una relazione primaria/secondaria, in cui solo l'app primaria è responsabile dei problemi di gestione delle chiavi e le app secondarie hanno semplicemente una visualizzazione di sola lettura dell'anello chiave. Le app secondarie possono essere configurate per considerare l'anello di chiave come di sola lettura configurando il sistema con DisableAutomaticKeyGeneration:

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

Isolamento per singola applicazione

Quando il sistema di protezione dei dati viene fornito da un host ASP.NET Core, isola automaticamente le app l'una dall'altra, anche se tali app vengono eseguite con lo stesso account del processo di lavoro e usano lo stesso materiale di master keying. È simile al modificatore IsolateApps dall'elemento system.Web <machineKey> .

Il meccanismo di isolamento funziona trattando ciascuna app sul computer locale come un tenant univoco, perciò la radice IDataProtector di qualsiasi app specifica include automaticamente l'ID dell'app come discriminante (ApplicationDiscriminator). L'ID univoco dell'app è il percorso fisico dell'app:

  • Per le app ospitate in IIS, l'ID univoco è il percorso fisico IIS dell'app. Se un'app viene distribuita in un ambiente web farm, questo valore è stabile presupponendo che gli ambienti IIS siano configurati in modo analogo in tutti i computer della Web farm.
  • Per le app self-hosted in esecuzione nel Kestrel server, l'ID univoco è il percorso fisico dell'app su disco.

L'identificatore univoco è progettato per sopravvivere alle reimpostazioni, sia della singola app che del computer stesso.

Questo meccanismo di isolamento presuppone che le app non siano dannose. Un'app dannosa può sempre influire su qualsiasi altra app in esecuzione con lo stesso account del processo di lavoro. In un ambiente di hosting condiviso in cui le app non sono attendibili a vicenda, il provider di hosting deve adottare misure per garantire l'isolamento a livello di sistema operativo tra le app, inclusa la separazione dei repository delle chiavi sottostanti delle app.

Se il sistema di protezione dati non viene fornito da un host ASP.NET Core (ad esempio, se si crea un'istanza tramite il tipo concreto DataProtectionProvider), l'isolamento dell'app è disabilitato per impostazione predefinita. Quando l'isolamento dell'app è disabilitato, tutte le app supportate dallo stesso materiale di keying possono condividere i payload purché forniscano gli scopi appropriati. Per fornire l'isolamento dell'app in questo ambiente, chiamare il metodo SetApplicationName nell'oggetto di configurazione e specificare un nome univoco per ogni app.

Protezione dei dati e isolamento delle app

Considerare i punti seguenti per l'isolamento delle app:

  • Quando più app puntano allo stesso repository di chiavi, l'intenzione è che le app condividano lo stesso materiale della chiave master. La protezione dei dati viene sviluppata presupponendo che tutte le app che condividono un anello di chiave possano accedere a tutti gli elementi dell'anello di chiave. L'identificatore univoco dell'applicazione viene usato per isolare le chiavi specifiche dell'applicazione derivate dalle chiavi fornite dall'anello di chiave. Non prevede autorizzazioni a livello di elemento, ad esempio quelle fornite da Azure KeyVault per applicare l'isolamento aggiuntivo. Il tentativo di autorizzazioni a livello di elemento genera errori dell'applicazione. Se non si vuole basarsi sull'isolamento predefinito dell'applicazione, è consigliabile usare posizioni separate dell'archivio chiavi e non condividere tra le applicazioni.

  • Il discriminante dell'applicazione (ApplicationDiscriminator) viene usato per consentire alle app diverse di condividere lo stesso materiale della chiave master, ma di mantenere i payload crittografici distinti l'uno dall'altro. Affinché le app possano leggere i payload crittografici degli altri, devono avere lo stesso discriminante dell'applicazione, che può essere impostato chiamando SetApplicationName.

  • Se un'app viene compromessa (ad esempio, da un attacco RCE), tutto il materiale della chiave master accessibile a tale app deve essere considerato compromesso, indipendentemente dal relativo stato di protezione inattivo. Ciò implica che se due app puntano allo stesso repository, anche se usano diversi discriminatori di app, un compromesso di uno è funzionalmente equivalente a un compromesso di entrambi.

    Questa clausola "funzionalmente equivalente a una compromissione di entrambe" rimane valida anche se le due app usano meccanismi diversi per la protezione delle chiavi a riposo. In genere, questa non è una configurazione prevista. Il meccanismo di protezione dei dati inattivi è progettato per fornire protezione nel caso in cui un eventuale attaccante informatico ottenga l'accesso in lettura al repository. Un cyberattacker che ottiene l'accesso in scrittura al repository (forse perché ha ottenuto l'autorizzazione di esecuzione del codice all'interno di un'app) può inserire chiavi dannose nella risorsa di archiviazione. Il sistema di protezione dei dati non fornisce intenzionalmente protezione da un cyberattacker che ottiene l'accesso in scrittura al repository delle chiavi.

  • Se le app devono rimanere veramente isolate l'una dall'altra, devono usare repository di chiavi diversi. Ciò non rientra naturalmente nella definizione di "isolato". Le app non sono isolate se hanno accesso in lettura e scrittura agli archivi dati delle altre.

Modifica degli algoritmi con UseCryptographicAlgorithms

Lo stack di protezione dati consente di modificare l'algoritmo predefinito usato dalle chiavi appena generate. Il modo più semplice per eseguire questa operazione consiste nel chiamare UseCryptographicAlgorithms dal callback di configurazione:

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

Il valore predefinito di EncryptionAlgorithm è AES-256-CBC e il valore predefinito ValidationAlgorithm è HMACSHA256. I criteri predefiniti possono essere impostati da un amministratore di sistema tramite un criterio valido per tutta la macchina, ma una chiamata esplicita per esegue l'override dei criteri predefiniti.

La chiamata UseCryptographicAlgorithms consente di specificare l'algoritmo desiderato da un elenco predefinito. Non è necessario preoccuparsi dell'implementazione dell'algoritmo. Nello scenario precedente, il sistema di protezione dei dati tenta di usare l'implementazione CNG di AES se in esecuzione in Windows. In caso contrario, effettua un fallback alla classe gestita System.Security.Cryptography.Aes.

È possibile specificare manualmente un'implementazione tramite una chiamata a UseCustomCryptographicAlgorithms.

Suggerimento

La modifica degli algoritmi non influisce sulle chiavi esistenti nell'anello di tasti. Influisce solo sulle chiavi appena generate.

Specificare algoritmi personalizzati gestiti

Per specificare algoritmi gestiti personalizzati, creare un'istanza ManagedAuthenticatedEncryptorConfiguration che punti ai tipi di implementazione:

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 genere, le proprietà *Type devono puntare a implementazioni concrete e istanziabili (tramite un costruttore pubblico senza parametri) di SymmetricAlgorithm e KeyedHashAlgorithm, sebbene il sistema gestisca in modo speciale alcuni valori come typeof(Aes) per praticità.

Nota

SymmetricAlgorithm deve avere una lunghezza della chiave di ≥ 128 bit e una dimensione del blocco di ≥ 64 bit e deve supportare la crittografia in modalità CBC con spaziatura interna PKCS #7. KeyedHashAlgorithm deve avere una dimensione digest pari >a = 128 bit e deve supportare chiavi di lunghezza uguale alla lunghezza del digest dell'algoritmo hash. Non è strettamente necessario che KeyedHashAlgorithm sia HMAC.

Specificare algoritmi personalizzati di Windows CNG

Per specificare un algoritmo CNG di Windows personalizzato usando la crittografia in modalità CBC con convalida HMAC, creare un'istanza CngCbcAuthenticatedEncryptorConfiguration contenente le informazioni algoritmiche:

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

        // Specified in bits
        EncryptionAlgorithmKeySize = 256,

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

Nota

L'algoritmo di crittografia a blocchi simmetrici deve avere una lunghezza della >chiave = 128 bit, una dimensione del blocco = >64 bit e deve supportare la crittografia in modalità CBC con spaziatura interna PKCS #7. L'algoritmo hash deve avere una dimensione del digest = >128 bit e deve supportare l'apertura con il flag BCRYPT_ALG_HANDLE_HMAC_FLAG. Le proprietà *Provider possono essere impostate su null per usare il provider predefinito per l'algoritmo specificato. Per altre informazioni, vedere la documentazione di BCryptOpenAlgorithmProvider .

Per specificare un algoritmo CNG di Windows personalizzato usando la crittografia galois/modalità contatore con la convalida, creare un'istanza CngGcmAuthenticatedEncryptorConfiguration contenente le informazioni algoritmiche:

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

        // Specified in bits
        EncryptionAlgorithmKeySize = 256
    });

Nota

L'algoritmo di crittografia a blocchi simmetrici deve avere una lunghezza della >chiave = 128 bit, una dimensione del blocco di esattamente 128 bit e deve supportare la crittografia GCM. È possibile impostare la EncryptionAlgorithmProvider proprietà su Null per utilizzare il provider predefinito per l'algoritmo specificato. Per altre informazioni, vedere la documentazione di BCryptOpenAlgorithmProvider .

Specifica di altri algoritmi personalizzati

Anche se non esposto come API di prima classe, il sistema di protezione dei dati è sufficientemente estensibile per consentire di specificare quasi qualsiasi tipo di algoritmo. Ad esempio, è possibile mantenere tutte le chiavi contenute in un modulo HSM (Hardware Security Module) e fornire un'implementazione personalizzata delle routine di crittografia e decrittografia principali. Per altre informazioni, vedere l'articolo IAuthenticatedEncryptor relativo all'estendibilità della crittografia core.

Permanenza delle chiavi durante l'hosting in un container Docker

Quando si ospita in un contenitore Docker , le chiavi devono essere mantenute in uno dei due casi seguenti:

Persistenza delle chiavi con Redis

Per archiviare le chiavi è necessario usare solo le versioni redis che supportano la persistenza dei dati Redis. L'archiviazione BLOB di Azure è persistente e può essere usata per archiviare le chiavi. Per altre informazioni, vedere questo problema in GitHub.

Registrazione

Abilita il livello di registrazione Information o inferiore per diagnosticare problemi. Il file seguente appsettings.json abilita la registrazione delle informazioni dell'API protezione dati:

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

Per altre informazioni sulla registrazione, vedere Registrazione in .NET Core e ASP.NET Core.

Risorse aggiuntive