Безопасное хранение секретов приложения во время развертывания в ASP.NET Core

Авторы: Рик Андерсон (Rick Anderson) и Кирк Ларкин (Kirk Larkin)

Просмотреть или скачать образец кода (как скачивать)

В этом документе объясняется, как управлять конфиденциальными данными для приложения ASP.NET Core на компьютере разработки. Никогда не храните пароли или другие конфиденциальные данные в исходном коде. Не следует использовать рабочие секреты для разработки или тестирования. Секреты не следует развертывать вместе с приложением. Вместо этого к рабочим секретам следует обращаться с помощью управляемых средств, таких как переменные среды или azure Key Vault. Для хранения и защиты секретов Azure в ходе тестирования и непосредственной работы используйте Поставщик конфигурации Azure Key Vault.

Сведения об использовании секретов пользователя в консольном приложении .NET см. в этой проблеме на GitHub.

Переменные среды

Переменные среды используются, чтобы избежать хранения секретов приложения в коде или в локальных файлах конфигурации. Переменные среды переопределяют значения конфигурации для всех ранее указанных источников конфигурации.

Рассмотрим ASP.NET Core веб-приложение, в котором включена безопасность отдельных учетных записей пользователей. Строка подключения к базе данных по умолчанию включается в файл проекта appsettings.json с ключом DefaultConnection. Строка подключения по умолчанию используется для LocalDB, которая выполняется в пользовательском режиме и не требует пароля. Во время развертывания DefaultConnection приложения значение ключа можно переопределить значением переменной среды. Переменная среды может хранить полную строку подключения с конфиденциальными учетными данными.

Предупреждение

Переменные среды обычно хранятся в простом незашифрованном тексте. Если компьютер или процесс скомпрометированы, ненадежные стороны могут получить доступ к переменным среды. Могут потребоваться дополнительные меры для предотвращения раскрытия секретов пользователей.

Разделитель : не работает с иерархическими ключами переменных среды на всех платформах. __ (двойной символ подчеркивания):

  • Поддерживается всеми платформами. Например, разделитель : не поддерживается Bash, а __ — поддерживается.
  • Автоматически заменяется на :

Диспетчер секретов

Средство Диспетчер секретов хранит конфиденциальные данные во время разработки проекта ASP.NET Core. В этом контексте часть конфиденциальных данных является секретом приложения. Секреты приложения хранятся в отдельном расположении от дерева проекта. Секреты приложения связаны с определенным проектом или совместно используются в нескольких проектах. Секреты приложения не регистрируются в системе управления версиями.

Предупреждение

Средство диспетчера секретов не шифрует сохраненные секреты и не должно рассматриваться как доверенное хранилище. Это только в целях разработки. Ключи и значения хранятся в JSфайле конфигурации ON в каталоге профиля пользователя.

Как работает средство диспетчера секретов

Средство диспетчера секретов скрывает сведения о реализации, например, где и как хранятся значения. Вы можете использовать средство, не зная эти сведения о реализации. Значения хранятся в JSфайле ON в папке профиля пользователя локального компьютера:

Путь к файловой системе:

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

В предыдущих путях к файлам замените <user_secrets_id> значением UserSecretsId , указанным в файле проекта.

Не записывайте код, который зависит от расположения или формата данных, сохраненных с помощью диспетчера секретов. Эти сведения о реализации могут измениться. Например, значения секретов не шифруются, но могут быть в будущем.

Включение хранилища секретов

Средство диспетчера секретов работает с параметрами конфигурации конкретного проекта, хранящимися в профиле пользователя.

Средство диспетчера секретов включает команду init . Чтобы использовать секреты пользователя, выполните следующую команду в каталоге проекта:

dotnet user-secrets init

Предыдущая команда добавляет UserSecretsId элемент в PropertyGroup файле проекта. По умолчанию внутренним текстом UserSecretsId является GUID. Внутренний текст является произвольным, но уникальным для проекта.

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

В Visual Studio щелкните правой кнопкой мыши проект в Обозреватель решений и выберите в контекстном меню пункт Управление секретами пользователя. Этот жест добавляет UserSecretsId элемент, заполненный ИДЕНТИФИКАТОРом GUID, в файл проекта.

Установка секрета

Определите секрет приложения, состоящий из ключа и его значения. Секрет связан со значением UserSecretsId проекта. Например, выполните следующую команду из каталога, в котором находится файл проекта:

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

В предыдущем примере двоеточие обозначает объектный Movies литерал со свойством ServiceApiKey .

Средство Диспетчер секретов можно использовать и из других каталогов. Используйте параметр , --project чтобы указать путь к файловой системе, по которому существует файл проекта. Пример:

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

JSВыравнивание структуры ON в Visual Studio

Жест Управления секретами пользователя в Visual Studio открывает secrets.json файл в текстовом редакторе. Замените содержимое secrets.json на пары "ключ-значение", которые будут сохранены. Пример:

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

Структура JSON преобразуется в плоскую структуру после внесения изменений с помощью dotnet user-secrets remove или dotnet user-secrets set. Например, при выполнении dotnet user-secrets remove "Movies:ConnectionString" выполняется свертывание литерала Movies объекта. Измененный файл выглядит следующим образом JS:

{
  "Movies:ServiceApiKey": "12345"
}

Установка нескольких секретов

Пакет секретов можно задать, указав в команде set ВКЛЮЧЕНОJS. В следующем примере содержимое input.json файла передается в set команду .

Откройте командную оболочку и выполните следующую команду:

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

Доступ к секрету

Чтобы получить доступ к секрету, выполните следующие действия.

  1. Регистрация источника конфигурации секретов пользователя
  2. Чтение секрета с помощью API конфигурации

Регистрация источника конфигурации секретов пользователя

Поставщик конфигурации секретов пользователя регистрирует соответствующий источник конфигурации в API конфигурации .NET.

Веб-приложения ASP.NET Core, созданные с помощью dotnet new или Visual Studio, создают следующий код:

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

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

app.Run();

WebApplication.CreateBuilder инициализирует новый экземпляр класса WebApplicationBuilder с предварительно настроенными значениями по умолчанию. Инициализированный WebApplicationBuilder (builder) предоставляет конфигурацию по умолчанию и вызывает AddUserSecrets , если EnvironmentName имеет значение Development:

Чтение секрета с помощью API конфигурации

Рассмотрим следующие примеры чтения Movies:ServiceApiKey ключа:

Файл Program.cs:

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

var app = builder.Build();

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

app.Run();

Razor Модель страниц Страницы:

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

Дополнительные сведения см. в разделе Конфигурация в ASP.NET Core.

Сопоставление секретов с POCO

Сопоставление всего литерала объекта с POCO (простой класс .NET со свойствами) полезно для агрегирования связанных свойств.

Предположим, что файл приложения secrets.json содержит следующие два секрета:

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

Чтобы сопоставить предыдущие секреты с POCO, используйте функцию привязки графа объектов API конфигурации .NET. Следующий код привязывается к пользовательскому MovieSettings POCO и обращается к значению ServiceApiKey свойства:

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

Секреты Movies:ConnectionString и Movies:ServiceApiKey сопоставляются с соответствующими свойствами в MovieSettings:

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

    public string ServiceApiKey { get; set; }
}

Замена строк секретами

Хранение паролей в виде обычного текста небезопасно. Например, строка подключения к базе данных, хранимая в appsettings.json , может содержать пароль для указанного пользователя:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;Password=pass123;MultipleActiveResultSets=true"
  }
}

Более безопасный подход заключается в хранении пароля в виде секрета. Пример:

dotnet user-secrets set "DbPassword" "pass123"

Password Удалите пару "ключ-значение" из строки подключения в appsettings.json. Пример:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;MultipleActiveResultSets=true"
  }
}

Значение секрета можно задать в свойстве SqlConnectionStringBuilder объекта Password для завершения строки подключения:

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

Перечисление секретов

Предположим, что файл приложения secrets.json содержит следующие два секрета:

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

Выполните следующую команду из каталога, в котором находится файл проекта:

dotnet user-secrets list

Отображаются следующие результаты:

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

В предыдущем примере двоеточие в именах ключей обозначает иерархию объектов в .secrets.json

Удаление одного секрета

Предположим, что файл приложения secrets.json содержит следующие два секрета:

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

Выполните следующую команду из каталога, в котором находится файл проекта:

dotnet user-secrets remove "Movies:ConnectionString"

Файл приложения secrets.json был изменен, чтобы удалить пару "ключ—значение", связанную с ключом Movies:ConnectionString :

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

dotnet user-secrets list отображает следующее сообщение:

Movies:ServiceApiKey = 12345

Удаление всех секретов

Предположим, что файл приложения secrets.json содержит следующие два секрета:

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

Выполните следующую команду из каталога, в котором находится файл проекта:

dotnet user-secrets clear

Все секреты пользователя для приложения были удалены из secrets.json файла:

{}

При выполнении dotnet user-secrets list отобразится следующее сообщение:

No secrets configured for this application.

Управление секретами пользователей с помощью Visual Studio

Чтобы управлять секретами пользователей в Visual Studio, щелкните правой кнопкой мыши проект в обозревателе решений и выберите Управление секретами пользователей:

В Visual Studio отображается управление секретами пользователей

Перенос секретов пользователей из ASP.NET Framework в ASP.NET Core

Также см. эту проблему в GitHub.

Дополнительные ресурсы

Рик Андерсон(Rick Anderson), Кирк Ларкин (Kirk Larkin),Дэниел Рот (Daniel Roth) и Скотт Эдди (Scott Addie)

Просмотреть или скачать образец кода (как скачивать)

В этом документе объясняется, как управлять конфиденциальными данными для приложения ASP.NET Core на компьютере разработки. Никогда не храните пароли или другие конфиденциальные данные в исходном коде. Секреты в рабочей среде не следует использовать для разработки или тестирования. Секреты не следует развертывать вместе с приложением. Вместо этого доступ к рабочим секретам должен осуществляться с помощью управляемых средств, таких как переменные среды или azure Key Vault. Для хранения и защиты секретов Azure в ходе тестирования и непосредственной работы используйте Поставщик конфигурации Azure Key Vault.

Переменные среды

Переменные среды используются для предотвращения хранения секретов приложения в коде или в локальных файлах конфигурации. Переменные среды переопределяют значения конфигурации для всех ранее указанных источников конфигурации.

Рассмотрим ASP.NET Core веб-приложение, в котором включена безопасность отдельных учетных записей пользователей. Строка подключения к базе данных по умолчанию включается в файл проекта appsettings.json с ключом DefaultConnection. Строка подключения по умолчанию — для LocalDB, которая выполняется в пользовательском режиме и не требует пароля. Во время развертывания DefaultConnection приложения значение ключа можно переопределить значением переменной среды. Переменная среды может хранить полную строку подключения с конфиденциальными учетными данными.

Предупреждение

Переменные среды обычно хранятся в простом незашифрованном тексте. Если компьютер или процесс скомпрометированы, доступ к переменным среды могут получить ненадежные стороны. Могут потребоваться дополнительные меры для предотвращения раскрытия секретов пользователей.

Разделитель : не работает с иерархическими ключами переменных среды на всех платформах. __ (двойной символ подчеркивания):

  • Поддерживается всеми платформами. Например, разделитель : не поддерживается Bash, а __ — поддерживается.
  • Автоматически заменяется на :

Диспетчер секретов

Средство Диспетчер секретов хранит конфиденциальные данные во время разработки проекта ASP.NET Core. В этом контексте часть конфиденциальных данных является секретом приложения. Секреты приложения хранятся в отдельном расположении от дерева проекта. Секреты приложения связаны с определенным проектом или совместно используются в нескольких проектах. Секреты приложения не регистрируются в системе управления версиями.

Предупреждение

Средство диспетчера секретов не шифрует хранимые секреты и не должно рассматриваться как доверенное хранилище. Это только для целей разработки. Ключи и значения хранятся в JSфайле конфигурации ON в каталоге профиля пользователя.

Как работает средство диспетчера секретов

Средство Диспетчер секретов скрывает сведения о реализации, например, где и как хранятся значения. Средство можно использовать, не зная этих сведений о реализации. Значения хранятся в on-файле JSв папке профиля пользователя локального компьютера:

Путь к файловой системе:

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

В предыдущих путях к файлам замените <user_secrets_id> значением UserSecretsId , указанным в файле проекта.

Не создавайте код, зависящий от расположения или формата данных, сохраненных с помощью средства Диспетчер секретов. Эти сведения о реализации могут измениться. Например, значения секретов не шифруются, но могут быть в будущем.

Включение хранилища секретов

Средство Диспетчер секретов работает с параметрами конфигурации конкретного проекта, хранящимися в профиле пользователя.

Средство Диспетчер секретов содержит команду в пакете init SDK для .NET Core 3.0.100 или более поздней версии. Чтобы использовать секреты пользователя, выполните следующую команду в каталоге проекта:

dotnet user-secrets init

Предыдущая команда добавляет UserSecretsId элемент в PropertyGroup элемент файла проекта. По умолчанию внутренним текстом UserSecretsId является GUID. Внутренний текст является произвольным, но уникальным для проекта.

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

В Visual Studio щелкните правой кнопкой мыши проект в Обозреватель решений и выберите в контекстном меню пункт Управление секретами пользователей. Этот жест добавляет UserSecretsId элемент, заполненный GUID, в файл проекта.

Установка секрета

Определите секрет приложения, состоящий из ключа и его значения. Секрет связан со значением UserSecretsId проекта. Например, выполните следующую команду из каталога, в котором находится файл проекта:

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

В предыдущем примере двоеточие обозначает объектный Movies литерал со свойством ServiceApiKey .

Средство Диспетчер секретов можно использовать и из других каталогов. Используйте параметр , --project чтобы указать путь к файловой системе, по которой существует файл проекта. Пример:

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

JSВыравнивание структуры ON в Visual Studio

Жест Управления секретами пользователя в Visual Studio открывает secrets.json файл в текстовом редакторе. Замените содержимое secrets.json на пары "ключ-значение", которые будут сохранены. Пример:

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

Структура JSON преобразуется в плоскую структуру после внесения изменений с помощью dotnet user-secrets remove или dotnet user-secrets set. Например, при выполнении dotnet user-secrets remove "Movies:ConnectionString" выполняется свертывание литерала Movies объекта. Измененный файл выглядит следующим образом JS:

{
  "Movies:ServiceApiKey": "12345"
}

Установка нескольких секретов

Пакет секретов можно задать, указав в команде set ВКЛЮЧЕНОJS. В следующем примере содержимое input.json файла передается в set команду .

Откройте командную оболочку и выполните следующую команду:

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

Доступ к секрету

Чтобы получить доступ к секрету, выполните следующие действия.

  1. Регистрация источника конфигурации секретов пользователя
  2. Чтение секрета с помощью API конфигурации

Регистрация источника конфигурации секретов пользователя

Поставщик конфигурации секретов пользователя регистрирует соответствующий источник конфигурации в API конфигурации .NET.

Источник конфигурации секретов пользователя автоматически добавляется в режиме разработки, когда проект вызывает CreateDefaultBuilder. CreateDefaultBuilder вызывает , AddUserSecretsEnvironmentName если имеет значение Development:

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

Если CreateDefaultBuilder не вызывается, добавьте источник конфигурации секретов пользователя явным образом, вызвав AddUserSecrets в ConfigureAppConfiguration. Вызовите AddUserSecrets только в том случае, если приложение выполняется в среде разработки, как показано в следующем примере:

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

Чтение секрета с помощью API конфигурации

Если источник конфигурации секретов пользователя зарегистрирован, API конфигурации .NET может считывать секреты. Внедрение конструктора можно использовать для получения доступа к API конфигурации .NET. Рассмотрим следующие примеры чтения Movies:ServiceApiKey ключа:

Класс запуска:

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 Модель страниц Страницы:

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

Дополнительные сведения см. в разделах Конфигурация Access в разделе Startup и Access configuration in Razor Pages.

Сопоставление секретов с POCO

Сопоставление всего литерала объекта с POCO (простой класс .NET со свойствами) полезно для агрегирования связанных свойств.

Предположим, что файл приложения secrets.json содержит следующие два секрета:

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

Чтобы сопоставить предыдущие секреты с POCO, используйте функцию привязки графа объектов API конфигурации .NET. Следующий код привязывается к пользовательскому MovieSettings объекту POCO и обращается к значению ServiceApiKey свойства:

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

Секреты Movies:ConnectionString и Movies:ServiceApiKey сопоставляются с соответствующими свойствами в MovieSettings:

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

    public string ServiceApiKey { get; set; }
}

Замена строк секретами

Хранение паролей в виде обычного текста небезопасно. Например, строка подключения к базе данных, хранящейся в , appsettings.json может содержать пароль для указанного пользователя:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;Password=pass123;MultipleActiveResultSets=true"
  }
}

Более безопасный подход заключается в хранении пароля в виде секрета. Пример:

dotnet user-secrets set "DbPassword" "pass123"

Password Удалите пару "ключ-значение" из строки подключения в appsettings.json. Пример:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;MultipleActiveResultSets=true"
  }
}

Значение секрета можно задать в свойстве SqlConnectionStringBuilderPassword объекта для завершения строки подключения:

public class Startup
{
    private string _connection = null;

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

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        var builder = new SqlConnectionStringBuilder(
            Configuration.GetConnectionString("Movies"));
        builder.Password = Configuration["DbPassword"];
        _connection = builder.ConnectionString;

        // code omitted for brevity
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            await context.Response.WriteAsync($"DB Connection: {_connection}");
        });
    }
}

Вывод списка секретов

Предположим, что файл приложения secrets.json содержит следующие два секрета:

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

Выполните следующую команду из каталога, в котором находится файл проекта:

dotnet user-secrets list

Отображаются следующие результаты:

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

В предыдущем примере двоеточие в именах ключей обозначает иерархию объектов в .secrets.json

Удаление одного секрета

Предположим, что файл приложения secrets.json содержит следующие два секрета:

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

Выполните следующую команду из каталога, в котором находится файл проекта:

dotnet user-secrets remove "Movies:ConnectionString"

Файл приложения secrets.json был изменен, чтобы удалить пару "ключ-значение", связанную с ключом MoviesConnectionString :

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

dotnet user-secrets list отображает следующее сообщение:

Movies:ServiceApiKey = 12345

Удаление всех секретов

Предположим, что файл приложения secrets.json содержит следующие два секрета:

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

Выполните следующую команду из каталога, в котором находится файл проекта:

dotnet user-secrets clear

Все секреты пользователя для приложения были удалены из secrets.json файла :

{}

При выполнении dotnet user-secrets list отобразится следующее сообщение:

No secrets configured for this application.

Управление секретами пользователей с помощью Visual Studio

Чтобы управлять секретами пользователей в Visual Studio, щелкните правой кнопкой мыши проект в обозревателе решений и выберите Управление секретами пользователей:

В Visual Studio отображается управление секретами пользователей

Перенос секретов пользователей из ASP.NET Framework в ASP.NET Core

Также см. эту проблему в GitHub.

Дополнительные ресурсы