Delen via


Niet-DI-bewuste scenario's voor gegevensbescherming in ASP.NET Core

Door Rick Anderson

Het ASP.NET Core Data Protection-systeem wordt normaal gesproken toegevoegd aan een servicecontainer en wordt gebruikt door afhankelijke onderdelen via afhankelijkheidsinjectie (DI). Er zijn echter gevallen waarin dit niet haalbaar of gewenst is, met name bij het importeren van het systeem in een bestaande app.

Ter ondersteuning van deze scenario's biedt het Microsoft.AspNetCore.DataProtection.Extensions-pakket een concreet type, DataProtectionProvider, dat een eenvoudige manier biedt om Gegevensbeveiliging te gebruiken zonder gebruik te maken van DI. Het type DataProtectionProvider implementeert IDataProtectionProvider. Voor het samenstellen van DataProtectionProvider is alleen een DirectoryInfo exemplaar vereist om aan te geven waar de cryptografische sleutels van de provider moeten worden opgeslagen, zoals te zien is in het volgende codevoorbeeld:

using System;
using System.IO;
using Microsoft.AspNetCore.DataProtection;

public class Program
{
    public static void Main(string[] args)
    {
        // Get the path to %LOCALAPPDATA%\myapp-keys
        var destFolder = Path.Combine(
            System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
            "myapp-keys");

        // Instantiate the data protection system at this folder
        var dataProtectionProvider = DataProtectionProvider.Create(
            new DirectoryInfo(destFolder));

        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        Console.Write("Enter input: ");
        var input = Console.ReadLine();

        // Protect the payload
        var protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");

        // Unprotect the payload
        var unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

        Console.WriteLine();
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Enter input: Hello world!
 * Protect returned: CfDJ8FWbAn6...ch3hAPm1NJA
 * Unprotect returned: Hello world!
 *
 * Press any key...
*/

Standaard versleutelt het DataProtectionProvider concrete-type het onbewerkte sleutelmateriaal niet voordat het naar het bestandssysteem wordt bewaard. Dit is bedoeld ter ondersteuning van scenario's waarbij de ontwikkelaar verwijst naar een netwerkshare en het gegevensbeschermingssysteem niet automatisch een geschikt versleutelingsmechanisme voor sleutels in rust kan afleiden.

Bovendien het DataProtectionProvider concrete type apps niet standaard isoleren. Alle apps die dezelfde sleutelmap gebruiken, kunnen nettoladingen delen zolang hun doelparameters overeenkomen.

De DataProtectionProvider constructor accepteert een optionele callback van configuraties die kan worden gebruikt om het gedrag van het systeem aan te passen. In het onderstaande voorbeeld ziet u hoe isolatie wordt hersteld met een expliciete aanroep naar SetApplicationName. In het voorbeeld ziet u ook hoe u het systeem configureert voor het automatisch versleutelen van persistente sleutels met behulp van Windows DPAPI. Als de map verwijst naar een UNC-share, kunt u een gedeeld certificaat distribueren over alle relevante computers en het systeem configureren voor het gebruik van versleuteling op basis van certificaten met een aanroep naar ProtectKeysWithCertificate.

using System;
using System.IO;
using Microsoft.AspNetCore.DataProtection;

public class Program
{
    public static void Main(string[] args)
    {
        // Get the path to %LOCALAPPDATA%\myapp-keys
        var destFolder = Path.Combine(
            System.Environment.GetEnvironmentVariable("LOCALAPPDATA"),
            "myapp-keys");

        // Instantiate the data protection system at this folder
        var dataProtectionProvider = DataProtectionProvider.Create(
            new DirectoryInfo(destFolder),
            configuration =>
            {
                configuration.SetApplicationName("my app name");
                configuration.ProtectKeysWithDpapi();
            });

        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        Console.Write("Enter input: ");
        var input = Console.ReadLine();

        // Protect the payload
        var protectedPayload = protector.Protect(input);
        Console.WriteLine($"Protect returned: {protectedPayload}");

        // Unprotect the payload
        var unprotectedPayload = protector.Unprotect(protectedPayload);
        Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

        Console.WriteLine();
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }
}

Tip

Exemplaren van het DataProtectionProvider betontype zijn duur om te maken. Als een app meerdere exemplaren van dit type onderhoudt en als ze allemaal dezelfde sleutelopslagmap gebruiken, kunnen de prestaties van de app afnemen. Als u het type DataProtectionProvider gebruikt, raden we u aan dit type eenmaal te maken en zo veel mogelijk opnieuw te gebruiken. Het DataProtectionProvider type en alle IDataProtector exemplaren die ermee zijn gemaakt, zijn thread-veilig voor meerdere bellers.