Bezpieczne przechowywanie tajemnic aplikacji podczas rozwoju w ASP.NET Core

Note

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.

Warning

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.

Autorzy: Rick Anderson i Kirk Larkin

W tym artykule wyjaśniono, jak zarządzać poufnymi danymi dla aplikacji ASP.NET Core na maszynie dewelopera. Nigdy nie przechowuj haseł ani innych poufnych danych w kodzie źródłowym lub plikach konfiguracji. Wpisy tajne produkcyjne nie powinny być używane do programowania ani testowania. Tajne dane nie powinny być wdrażane razem z aplikacją. Dostęp do sekretów produkcyjnych należy uzyskać za pośrednictwem kontrolowanych środków, takich jak usługa Azure Key Vault. Tajemnice testowania i produkcji Azure można przechowywać i chronić za pomocą dostawcy konfiguracji Azure Key Vault.

Wyświetlanie lub pobieranie przykładowego kodu (jak pobrać)

Aby uzyskać więcej informacji na temat uwierzytelniania dla wdrożonych aplikacji testowych i produkcyjnych, zobacz Bezpieczne przepływy uwierzytelniania.

Aby skorzystać z wpisów tajnych użytkownika w aplikacji konsolowej .NET, zobacz zgłoszenie #3939 w repozytorium GitHub dotnet/entityframework.docs.

Praca ze zmiennymi środowiskowymi

Zmienne środowiskowe służą do unikania przechowywania tajnych danych aplikacji w kodzie lub w lokalnych plikach konfiguracji. Zmienne środowiskowe zastępują wartości konfiguracji dla wszystkich wcześniej określonych źródeł konfiguracji.

Rozważ aplikację internetową ASP.NET Core, w której włączone są zabezpieczenia Indywidualnych Kont. Domyślny ciąg połączenia z bazą danych jest zawarty w pliku projektu appsettings.json pod kluczem DefaultConnection. Domyślny ciąg połączenia to LocalDB, który działa w trybie użytkownika i nie wymaga hasła. Podczas wdrażania aplikacji można zastąpić DefaultConnection wartość klucza wartością ze zmiennej środowiskowej. Zmienna środowiskowa może przechowywać pełne parametry połączenia wraz z poufnymi poświadczeniami.

Warning

Zmienne środowiskowe są często przechowywane jako zwykły, niezaszyfrowany tekst. W przypadku naruszenia zabezpieczeń maszyny lub procesu zmienne środowiskowe są dostępne dla niezaufanych stron. Mogą być wymagane dodatkowe środki, aby zapobiec ujawnieniu wpisów tajnych użytkownika.

Separator dwukropkowy (:) nie działa z kluczami hierarchicznymi zmiennych środowiskowych na wszystkich platformach. Na przykład Bash nie obsługuje dwukropka (:) jako separatora. Wszystkie platformy obsługują składnię podwójnego znaku podkreślenia (__) i automatycznie zastępują go dwukropkiem (:).

Korzystanie z narzędzia Secret Manager

Secret Manager to narzędzie, które przechowuje poufne dane podczas tworzenia aplikacji. W tym kontekście jednym z poufnych danych jest klucz tajny aplikacji.

  • Tajne dane aplikacji są przechowywane w lokalizacji oddzielonej od drzewa projektu.
  • Są one skojarzone z określonym projektem lub współużytkowane w kilku projektach.
  • Nie są one zaewidencjonowane w kontroli źródła.

Warning

Secret Manager nie szyfruje przechowywanych sekretów i nie należy traktować go jako zaufanego miejsca przechowywania. Jest to tylko do celów programistycznych. Klucze i wartości są przechowywane w pliku konfiguracji JSON w katalogu profilu użytkownika.

Menedżer sekretów ukrywa szczegóły implementacji, takie jak to, gdzie i w jaki sposób przechowywane są wartości. Możesz użyć narzędzia bez znajomości tych szczegółów implementacji. Wartości są przechowywane w pliku JSON w folderze profilu użytkownika komputera lokalnego:

Ścieżka systemu plików:

%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json

W ścieżce systemu plików zastąp <user_secrets_id> część wartością UserSecretsId określoną w pliku projektu.

Nie zapisuj kodu, który zależy od lokalizacji lub formatu danych zapisanych w programie Secret Manager. Te szczegóły implementacji mogą ulec zmianie. Na przykład tajne wartości nie są szyfrowane.

Włącz magazyn tajny

Menedżer sekretów działa w oparciu o ustawienia konfiguracji specyficzne dla projektu przechowywane w Twoim profilu użytkownika.

Użyj interfejsu wiersza poleceń

Menedżer sekretów zawiera polecenie init. Aby użyć tajemnic użytkownika, uruchom następujące polecenie w katalogu projektu.

dotnet user-secrets init

To polecenie dodaje element UserSecretsId wewnątrz elementu PropertyGroup pliku projektu. Domyślnie wewnętrzny tekst UserSecretsId to identyfikator GUID. Tekst wewnętrzny jest dowolny, ale jest unikatowy dla projektu. W poniższym przykładzie przedstawiono wartość identyfikatora GUID .0000a1a1-b2b2-c3c3-d4d4-eeeeee555555

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <UserSecretsId>0000a1a1-b2b2-c3c3-d4d4-eeeeee555555</UserSecretsId>
  </PropertyGroup>

</Project>

Korzystanie z programu Visual Studio

W programie Visual Studio kliknij prawym przyciskiem myszy projekt w Eksploratorze Rozwiązań, a następnie z menu kontekstowego wybierz polecenie Zarządzaj tajnymi danymi użytkownika. Ten gest dodaje element UserSecretsId, wypełniony GUID-em, do pliku projektu.

Jeśli „GenerateAssemblyInfo” ma wartość „false”

Jeśli generowanie atrybutów informacji o zestawie () jest wyłączone (GenerateAssemblyInfoustawione na false), ręcznie dodaj element UserSecretsIdAttribute w pliku AssemblyInfo.cs . Przykład:

[assembly: UserSecretsId("your_user_secrets_id")]

Po ręcznym dodaniu atrybutu UserSecretsId do pliku UserSecretsId wartość musi być zgodna z wartością w pliku projektu.

Ustaw tajne

Zdefiniuj tajemnicę aplikacji składającą się z klucza i jego wartości. Tajemnica jest skojarzona z wartością UserSecretsId projektu. Na przykład uruchom następujące polecenie z katalogu, w którym istnieje plik projektu:

dotnet user-secrets set "Movies:ServiceApiKey" "12345"

W tym przykładzie dwukropek wskazuje, że Movies jest to literał obiektu z właściwością ServiceApiKey .

Można również używać Secret Manager w innych katalogach. --project Dołącz opcję, aby podać ścieżkę systemu plików, w której istnieje plik projektu. Przykład:

dotnet user-secrets set "Movies:ServiceApiKey" "12345" --project "C:\apps\WebApp1\src\WebApp1"

Spłaszczanie struktury JSON w programie Visual Studio

Polecenie programu Visual Studio Manage User Secrets otwiera plik secrets.json w edytorze tekstu. Zastąp zawartość pliku secrets.json parami klucz-wartość, które mają być przechowywane. Przykład:

{
  "Movies": {
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
    "ServiceApiKey": "12345"
  }
}

Struktura JSON zostaje spłaszczona po wprowadzeniu modyfikacji za pomocą polecenia dotnet user-secrets remove lub dotnet user-secrets set. Na przykład uruchomienie dotnet user-secrets remove "Movies:ConnectionString" zwija Movies literał obiektu. Zmodyfikowany plik przypomina następujący kod JSON:

{
  "Movies:ServiceApiKey": "12345"
}

Ustawianie wielu sekretów

Partię tajnych można ustawić, przekazując kod JSON do polecenia set. W poniższym przykładzie zawartość pliku input.json jest przekazywana potokowo do polecenia set.

Uruchom następujące polecenie:

type .\input.json | dotnet user-secrets set

Dostęp do tajnego

Aby uzyskać dostęp do wpisu tajnego, wykonaj następujące kroki:

  1. Zarejestruj źródło konfiguracji sekretów użytkownika.

  2. Odczytaj klucz tajny za pośrednictwem interfejsu API konfiguracji.

Zarejestruj źródło konfiguracji tajnych danych użytkownika

Dostawca konfiguracji tajnych danych użytkownika rejestruje odpowiednie źródło konfiguracji w interfejsie API do konfiguracji platformy .NET.

Aplikacje internetowe ASP.NET Core utworzone za pomocą polecenia dotnet new lub programu Visual Studio generują następujący kod:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Metoda WebApplication.CreateBuilder inicjuje nowe wystąpienie WebApplicationBuilder klasy z wstępnie skonfigurowanymi wartościami domyślnymi. Zainicjowany WebApplicationBuilder (builder) zapewnia domyślną konfigurację i wywołuje metodę AddUserSecrets, gdy właściwość EnvironmentName ma wartość Development.

Odczytywanie tajnego hasła przez interfejs API konfiguracji.

Poniższe przykłady pokazują, jak odczytywać klucz Movies:ServiceApiKey:

plik Program.cs

var builder = WebApplication.CreateBuilder(args);
var movieApiKey = builder.Configuration["Movies:ServiceApiKey"];

var app = builder.Build();

app.MapGet("/", () => movieApiKey);

app.Run();

Razor Model strony stron

public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public void OnGet()
    {
        var moviesApiKey = _config["Movies:ServiceApiKey"];

        // call Movies service with the API key
    }
}

Aby uzyskać więcej informacji, zobacz Konfiguracja na platformie ASP.NET Core.

Mapowanie sekretów na obiekt POCO

Mapowanie całego literału obiektu na obiekt POCO (prosta klasa .NET z właściwościami) jest przydatne w przypadku agregowania powiązanych właściwości.

Załóżmy, że plik secrets.json aplikacji zawiera następujące dwa wpisy tajne:

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

Aby zamapować wcześniej wspomniane tajne informacje na obiekt POCO, użyj funkcji wiązania grafu obiektów w interfejsie API konfiguracji .NET. Poniższy kod wiąże się z niestandardowym MovieSettings elementem POCO i uzyskuje wartość właściwości z ServiceApiKey.

var moviesConfig = 
    Configuration.GetSection("Movies").Get<MovieSettings>();
_moviesApiKey = moviesConfig.ServiceApiKey;

Wartości Movies:ConnectionString i Movies:ServiceApiKey są mapowane na odpowiednie właściwości w MovieSettings:

public class MovieSettings
{
    public string ConnectionString { get; set; }

    public string ServiceApiKey { get; set; }
}

Używanie zamiany ciągu z wpisami tajnymi

Przechowywanie haseł w postaci zwykłego tekstu jest niezabezpieczone. Nigdy nie przechowuj wpisów tajnych w pliku konfiguracji, takim jak appsettings.json, co może zostać zaewidencjonowane w repozytorium kodu źródłowego.

Na przykład parametry połączenia z bazą danych przechowywane w pliku appsettings.json nie powinny zawierać hasła. Zamiast tego należy przechowywać hasło jako sekret i dołączać je do parametrów ciągu połączenia w czasie wykonywania. Przykład:

dotnet user-secrets set "DbPassword" "`<secret value>`"

Zastąp symbol zastępczy <secret value> w przykładzie wartością hasła. Ustaw wartość wpisu tajnego SqlConnectionStringBuilder we właściwości obiektuPassword, aby uwzględnić ją jako wartość hasła w parametry połączenia:

using System.Data.SqlClient;

var builder = WebApplication.CreateBuilder(args);

var conStrBuilder = new SqlConnectionStringBuilder(
        builder.Configuration.GetConnectionString("Movies"));
conStrBuilder.Password = builder.Configuration["DbPassword"];
var connection = conStrBuilder.ConnectionString;

var app = builder.Build();

app.MapGet("/", () => connection);

app.Run();

Lista tajemnic

Załóżmy, że plik secrets.json aplikacji zawiera następujące dwa wpisy tajne:

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

Uruchom następujące polecenie z katalogu, w którym istnieje plik projektu:

dotnet user-secrets list

Wyświetlane są następujące dane wyjściowe:

Movies:ConnectionString = Server=(localdb)\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true
Movies:ServiceApiKey = 12345

W tym przykładzie dwukropek (:) w nazwach kluczy określa hierarchię obiektów w pliku secrets.json .

Usuń pojedynczą tajemnicę

Załóżmy, że plik secrets.json aplikacji zawiera następujące dwa wpisy tajne:

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

Uruchom następujące polecenie z katalogu, w którym istnieje plik projektu:

dotnet user-secrets remove "Movies:ConnectionString"

Plik secrets.json aplikacji jest modyfikowany w celu usunięcia pary klucz-wartość skojarzonej z kluczem Movies:ConnectionString :

{
  "Movies": {
    "ServiceApiKey": "12345"
  }
}

Polecenie dotnet user-secrets list wyświetla następujący komunikat:

Movies:ServiceApiKey = 12345

Usuń wszystkie wpisy tajne

Załóżmy, że plik secrets.json aplikacji zawiera następujące dwa wpisy tajne:

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

Uruchom następujące polecenie z katalogu, w którym istnieje plik projektu:

dotnet user-secrets clear

Wszystkie wpisy tajne użytkownika dla aplikacji są usuwane z pliku secrets.json :

{}

Uruchomienie polecenia powoduje wyświetlenie następującego komunikatu dotnet user-secrets list :

No secrets configured for this application.

Zarządzanie wpisami tajnymi użytkownika za pomocą programu Visual Studio

Aby zarządzać wpisami tajnymi użytkownika w Visual Studio, kliknij prawym przyciskiem myszy projekt w Eksplorator rozwiązań i wybierz pozycję Zarządzaj wpisami tajnymi użytkownika:

Screenshot pokazuje, jak wybrać opcję Zarządzaj wpisami tajnymi użytkownika w Visual Studio.

Migrowanie wpisów tajnych użytkownika z programu ASP.NET Framework do ASP.NET Core

Możesz przeprowadzić migrację przechowywanych wpisów tajnych użytkownika z programu ASP.NET Framework do ASP.NET Core. Aby uzyskać więcej informacji, zobacz problem GitHub dotnet/aspnetcore.docs nr 27611 - dokumentacja funkcji Tajemnice użytkownika nie wspomina o niezgodności z plikiem AssemblyInfo.cs.

Praca z wpisami tajnymi użytkownika w aplikacjach nieinternetowych

Projekty przeznaczone Microsoft.NET.Sdk.Web automatycznie obejmują obsługę tajemnic użytkownika. W przypadku projektów przeznaczonych dla Microsoft.NET.Sdk, takich jak aplikacje konsolowe, zainstaluj pakiety NuGet rozszerzenia konfiguracji i tajnych danych użytkownika.

Install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.Configuration.UserSecrets

Po zainstalowaniu pakietów zainicjuj projekt i ustaw wpisy tajne tak samo jak w przypadku aplikacji internetowej. Poniższy przykład przedstawia aplikację konsolową, która pobiera wartość klucza tajnego ustawionego przy użyciu klucza AppSecret:

using Microsoft.Extensions.Configuration;

namespace ConsoleApp;

class Program
{
    static void Main(string[] args)
    {
        IConfigurationRoot config = new ConfigurationBuilder()
            .AddUserSecrets<Program>()
            .Build();

        Console.WriteLine(config["AppSecret"]);
    }
}

Autor : Rick Anderson, Kirk Larkin, Daniel Roth i Scott Addie

Wyświetl lub pobierz przykładowy kod (jak pobrać)

W tym artykule wyjaśniono, jak zarządzać poufnymi danymi dla aplikacji ASP.NET Core na maszynie dewelopera. Nigdy nie przechowuj haseł ani innych poufnych danych w kodzie źródłowym lub plikach konfiguracji. Wpisy tajne produkcyjne nie powinny być używane do programowania ani testowania. Tajne dane nie powinny być wdrażane razem z aplikacją. Dostęp do sekretów produkcyjnych należy uzyskać za pośrednictwem kontrolowanych środków, takich jak usługa Azure Key Vault. Tajemnice testowania i produkcji Azure można przechowywać i chronić za pomocą dostawcy konfiguracji Azure Key Vault.

Aby uzyskać więcej informacji na temat uwierzytelniania w środowiskach testowych i produkcyjnych, zobacz Bezpieczne przepływy uwierzytelniania.

Zmienne środowiskowe

Zmienne środowiskowe służą do unikania przechowywania tajnych danych aplikacji w kodzie lub w lokalnych plikach konfiguracji. Zmienne środowiskowe zastępują wartości konfiguracji dla wszystkich wcześniej określonych źródeł konfiguracji.

Rozważmy aplikację internetową ASP.NET Core, w której włączono zabezpieczenia poszczególnych kont użytkowników. Domyślny parametr połączenia do bazy danych jest zawarty w pliku projektu appsettings.json z kluczem DefaultConnection. Domyślny ciąg połączenia to LocalDB, który działa w trybie użytkownika i nie wymaga hasła. Podczas wdrażania DefaultConnection aplikacji wartość klucza może zostać zastąpiona wartością zmiennej środowiskowej. Zmienna środowiskowa może przechowywać kompletny ciąg połączenia z poufnymi poświadczeniami.

Warning

Zmienne środowiskowe są zwykle przechowywane w postaci zwykłego, niezaszyfrowanego tekstu. W przypadku naruszenia zabezpieczeń maszyny lub procesu zmienne środowiskowe mogą być dostępne dla niezaufanych stron. Mogą być wymagane dodatkowe środki zapobiegające ujawnieniu wpisów tajnych użytkownika.

Separator dwukropkowy (:) nie działa z kluczami hierarchicznymi zmiennych środowiskowych na wszystkich platformach. Na przykład Bash nie obsługuje dwukropka (:) jako separatora. Wszystkie platformy obsługują składnię podwójnego znaku podkreślenia (__) i automatycznie zastępują go dwukropkiem (:).

Menedżer tajemnic

Narzędzie Secret Manager przechowuje poufne dane podczas tworzenia aplikacji. W tym kontekście część danych poufnych to sekret aplikacji. Tajne dane aplikacji są przechowywane w lokalizacji oddzielonej od drzewa projektu. Sekrety aplikacji są skojarzone z określonym projektem lub współdzielone w kilku projektach. Sekrety aplikacji nie są przechowywane w systemie kontroli wersji.

Warning

Narzędzie Secret Manager nie szyfruje przechowywanych tajemnic i nie należy traktować jako zaufanego magazynu. Jest to tylko do celów programistycznych. Klucze i wartości są przechowywane w pliku konfiguracji JSON w katalogu profilu użytkownika.

Jak działa narzędzie Secret Manager

Narzędzie Secret Manager ukrywa szczegóły implementacji, takie jak miejsce i sposób przechowywania wartości. Możesz użyć narzędzia bez znajomości tych szczegółów implementacji. Wartości są przechowywane w pliku JSON w folderze profilu użytkownika komputera lokalnego:

Ścieżka systemu plików:

%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json

W poprzednich ścieżkach plików zastąp <user_secrets_id> wartością UserSecretsId określoną w pliku projektu.

Nie zapisuj kodu, który zależy od lokalizacji lub formatu danych zapisanych za pomocą narzędzia Secret Manager. Te szczegóły implementacji mogą ulec zmianie. Na przykład sekretne wartości nie są szyfrowane, ale mogą być w przyszłości.

Włącz magazyn tajny

Narzędzie Secret Manager działa na ustawieniach konfiguracji specyficznych dla projektu przechowywanych w profilu użytkownika.

Narzędzie Secret Manager zawiera init polecenie w zestawach .NET Core SDK 3.0.100 lub nowszym. Aby użyć tajemnic użytkownika, uruchom następujące polecenie w katalogu projektu.

dotnet user-secrets init

Poprzednie polecenie dodaje element UserSecretsId w PropertyGroup pliku projektu. Domyślnie wewnętrzny tekst UserSecretsId to identyfikator GUID. Tekst wewnętrzny jest dowolny, ale jest unikatowy dla projektu.

<PropertyGroup>
  <TargetFramework>netcoreapp3.1</TargetFramework>
  <UserSecretsId>79a3edd0-2092-40a2-a04d-dcb46d5ca9ed</UserSecretsId>
</PropertyGroup>

W programie Visual Studio kliknij prawym przyciskiem myszy projekt w Eksploratorze Rozwiązań, a następnie z menu kontekstowego wybierz polecenie Zarządzaj tajnymi danymi użytkownika. Ten gest dodaje element UserSecretsId, wypełniony GUID-em, do pliku projektu.

Ustaw tajne

Zdefiniuj tajemnicę aplikacji składającą się z klucza i jego wartości. Tajemnica jest skojarzona z wartością UserSecretsId projektu. Na przykład uruchom następujące polecenie z katalogu, w którym istnieje plik projektu:

dotnet user-secrets set "Movies:ServiceApiKey" "12345"

W poprzednim przykładzie dwukropek oznacza, że Movies jest literałem obiektu z właściwością ServiceApiKey.

Narzędzie Secret Manager może być również używane z innych katalogów. --project Użyj opcji , aby podać ścieżkę systemu plików, w której istnieje plik projektu. Przykład:

dotnet user-secrets set "Movies:ServiceApiKey" "12345" --project "C:\apps\WebApp1\src\WebApp1"

Spłaszczanie struktury JSON w programie Visual Studio

Gest Zarządzaj wpisami tajnymi użytkownika programu Visual Studio otwiera secrets.json plik w edytorze tekstowym. Zastąp zawartość secrets.json par klucz-wartość, które mają być przechowywane. Przykład:

{
  "Movies": {
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
    "ServiceApiKey": "12345"
  }
}

Struktura JSON jest spłaszczana po modyfikacjach za pośrednictwem metody dotnet user-secrets remove lub dotnet user-secrets set. Na przykład uruchomienie dotnet user-secrets remove "Movies:ConnectionString" zwija Movies literał obiektu. Zmodyfikowany plik przypomina następujący kod JSON:

{
  "Movies:ServiceApiKey": "12345"
}

Ustawianie wielu sekretów

Partię tajnych można ustawić, przekazując kod JSON do polecenia set. W poniższym przykładzie input.json zawartość pliku jest potokowana do set polecenia .

Otwórz konsolę poleceń i wykonaj następujące polecenie:

type .\input.json | dotnet user-secrets set

Dostęp do tajnego

Aby uzyskać dostęp do wpisu tajnego, wykonaj następujące kroki:

  1. Rejestrowanie źródła konfiguracji sekretów użytkownika
  2. Odczytywanie wpisu tajnego za pośrednictwem interfejsu API konfiguracji

Zarejestruj źródło konfiguracji tajnych danych użytkownika

Dostawca konfiguracji tajnych danych użytkownika rejestruje odpowiednie źródło konfiguracji w interfejsie API do konfiguracji platformy .NET.

Źródło konfiguracji tajemnic użytkownika jest automatycznie dodawane w trybie deweloperskim, gdy projekt wywołuje CreateDefaultBuilder. CreateDefaultBuilder wywołuje AddUserSecrets, gdy EnvironmentName jest Development.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

Jeśli CreateDefaultBuilder nie jest wywoływana, dodaj źródło konfiguracji tajnych użytkownika poprzez wywołanie AddUserSecrets w ConfigureAppConfiguration. Wywołaj AddUserSecrets tylko wtedy, gdy aplikacja działa w środowisku Development, jak pokazano w przykładzie poniżej:

public class Program
{
    public static void Main(string[] args)
    {
        var host = new HostBuilder()
            .ConfigureAppConfiguration((hostContext, builder) =>
            {
                // Add other providers for JSON, etc.

                if (hostContext.HostingEnvironment.IsDevelopment())
                {
                    builder.AddUserSecrets<Program>();
                }
            })
            .Build();
        
        host.Run();
    }
}

Odczytywanie tajnego hasła przez interfejs API konfiguracji.

Jeśli źródło konfiguracji wpisów tajnych użytkownika jest zarejestrowane, interfejs API konfiguracji platformy .NET może odczytywać wpisy tajne. Iniekcja konstruktora może być używana do uzyskiwania dostępu do interfejsu API konfiguracji platformy .NET. Rozważmy następujące przykłady odczytywania Movies:ServiceApiKey klucza:

Klasa uruchamiania:

public class Startup
{
    private string _moviesApiKey = null;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        _moviesApiKey = Configuration["Movies:ServiceApiKey"];
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            var result = string.IsNullOrEmpty(_moviesApiKey) ? "Null" : "Not Null";
            await context.Response.WriteAsync($"Secret is {result}");
        });
    }
}

Razor Model strony stron:

public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public void OnGet()
    {
        var moviesApiKey = _config["Movies:ServiceApiKey"];

        // call Movies service with the API key
    }
}

Aby uzyskać więcej informacji, zobacz Konfiguracja dostępu w Uruchamianiu i Konfiguracja dostępu na Razor Stronach.

Mapowanie sekretów na obiekt POCO

Mapowanie całego literału obiektu na obiekt POCO (prosta klasa .NET z właściwościami) jest przydatne w przypadku agregowania powiązanych właściwości.

Załóżmy, że plik secrets.json aplikacji zawiera następujące dwa wpisy tajne:

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

Aby zamapować wcześniej wspomniane tajne informacje na obiekt POCO, użyj funkcji wiązania grafu obiektów w interfejsie API konfiguracji .NET. Poniższy kod wiąże się z niestandardowym MovieSettings elementem POCO i uzyskuje wartość właściwości z ServiceApiKey.

var moviesConfig = 
    Configuration.GetSection("Movies").Get<MovieSettings>();
_moviesApiKey = moviesConfig.ServiceApiKey;

Wartości Movies:ConnectionString i Movies:ServiceApiKey są mapowane na odpowiednie właściwości w MovieSettings:

public class MovieSettings
{
    public string ConnectionString { get; set; }

    public string ServiceApiKey { get; set; }
}

Zastępowanie łańcucha tajnymi danymi

Przechowywanie haseł w postaci zwykłego tekstu jest niezabezpieczone. Nigdy nie przechowuj wpisów tajnych w pliku konfiguracji, takim jak appsettings.json, co może zostać zaewidencjonowane w repozytorium kodu źródłowego.

Na przykład, łańcuch połączenia do bazy danych przechowywany w appsettings.json nie powinien zawierać hasła. Zamiast tego należy przechowywać hasło jako sekret i dołączać je do parametrów ciągu połączenia w czasie wykonywania. Przykład:

dotnet user-secrets set "DbPassword" "<secret value>"

Zamień symbol <secret value> w poprzednim przykładzie na wartość hasła. Ustaw wartość wpisu tajnego SqlConnectionStringBuilder we właściwości obiektuPassword, aby uwzględnić ją jako wartość hasła w parametry połączenia:

using System.Data.SqlClient;

var builder = WebApplication.CreateBuilder(args);

var conStrBuilder = new SqlConnectionStringBuilder(
        builder.Configuration.GetConnectionString("Movies"));
conStrBuilder.Password = builder.Configuration["DbPassword"];
var connection = conStrBuilder.ConnectionString;

var app = builder.Build();

app.MapGet("/", () => connection);

app.Run();

Lista tajemnic

Załóżmy, że plik secrets.json aplikacji zawiera następujące dwa wpisy tajne:

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

Uruchom następujące polecenie z katalogu, w którym istnieje plik projektu:

dotnet user-secrets list

Wyświetlane są następujące dane wyjściowe:

Movies:ConnectionString = Server=(localdb)\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true
Movies:ServiceApiKey = 12345

W poprzednim przykładzie dwukropek w nazwach kluczy określa hierarchię obiektów w programie secrets.json.

Usuń pojedynczą tajemnicę

Załóżmy, że plik secrets.json aplikacji zawiera następujące dwa wpisy tajne:

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

Uruchom następujące polecenie z katalogu, w którym istnieje plik projektu:

dotnet user-secrets remove "Movies:ConnectionString"

Plik aplikacji secrets.json został zmodyfikowany w celu usunięcia pary klucz-wartość skojarzonej z kluczem MoviesConnectionString :

{
  "Movies": {
    "ServiceApiKey": "12345"
  }
}

dotnet user-secrets list wyświetla następujący komunikat:

Movies:ServiceApiKey = 12345

Usuń wszystkie wpisy tajne

Załóżmy, że plik secrets.json aplikacji zawiera następujące dwa wpisy tajne:

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

Uruchom następujące polecenie z katalogu, w którym istnieje plik projektu:

dotnet user-secrets clear

Wszystkie wpisy tajne użytkownika dla aplikacji zostały usunięte z secrets.json pliku:

{}

Uruchomienie dotnet user-secrets list powoduje wyświetlenie następującego komunikatu:

No secrets configured for this application.

Zarządzanie wpisami tajnymi użytkownika za pomocą programu Visual Studio

Aby zarządzać wpisami tajnymi użytkownika w programie Visual Studio, kliknij prawym przyciskiem myszy projekt w Eksploratorze rozwiązań i wybierz polecenie Zarządzaj wpisami tajnymi użytkownika:

Program Visual Studio przedstawiający zarządzanie wpisami tajnymi użytkownika

Migrowanie tajnych danych użytkownika z ASP.NET do ASP.NET Core

Zobacz ten problem z usługą GitHub.

Wpisy tajne użytkownika w aplikacjach innych niż internetowe

Projekty przeznaczone Microsoft.NET.Sdk.Web automatycznie obejmują obsługę tajemnic użytkownika. W przypadku projektów przeznaczonych dla Microsoft.NET.Sdk, takich jak aplikacje konsolowe, zainstaluj pakiety NuGet rozszerzenia konfiguracji i tajnych danych użytkownika.

Korzystanie z programu PowerShell:

Install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.Configuration.UserSecrets

Korzystanie z interfejsu wiersza polecenia platformy .NET:

dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.UserSecrets

Po zainstalowaniu pakietów zainicjuj projekt i ustaw wpisy tajne w taki sam sposób jak w przypadku aplikacji internetowej. W poniższym przykładzie pokazano aplikację konsolową, która pobiera wartość sekretu ustawionego przy użyciu klucza "AppSecret".

using Microsoft.Extensions.Configuration;

namespace ConsoleApp;

class Program
{
    static void Main(string[] args)
    {
        IConfigurationRoot config = new ConfigurationBuilder()
            .AddUserSecrets<Program>()
            .Build();

        Console.WriteLine(config["AppSecret"]);
    }
}

Dodatkowe zasoby