Safe storage of app secrets in development in ASP.NET Core(ASP.NET Core에서 개발 중인 앱 비밀의 안전한 스토리지)

Rick Anderson, Kirk Larkin, Daniel RothScott addie

예제 코드 살펴보기 및 다운로드 (다운로드 방법)

이 문서에서는 개발 컴퓨터에서 ASP.NET Core 앱에 대 한 중요 한 데이터를 관리 하는 방법을 설명 합니다. 암호 또는 기타 중요 한 데이터를 소스 코드에 저장 하지 마세요. 프로덕션 암호는 개발 또는 테스트에 사용할 수 없습니다. 암호는 앱과 함께 배포 해서는 안 됩니다. 대신 환경 변수 또는 Azure Key Vault 같은 제어 된 방법을 통해 프로덕션 비밀에 액세스 해야 합니다. Azure Key Vault 구성 제공자로 Azure 테스트 및 프로덕션 암호를 저장하고 보호할 수 있습니다.

환경 변수

환경 변수는 코드 또는 로컬 구성 파일에서 앱 암호의 저장을 방지 하는 데 사용 됩니다. 환경 변수는 이전에 지정 된 모든 구성 소스에 대 한 구성 값을 재정의 합니다.

개별 사용자 계정 보안이 사용 되는 ASP.NET Core 웹 앱을 고려 합니다. 기본 데이터베이스 연결 문자열은 키가 있는 프로젝트의 파일에 포함 됩니다 appsettings.json DefaultConnection . 기본 연결 문자열은 사용자 모드로 실행 되 고 암호를 요구 하지 않는 LocalDB에 대 한 것입니다. 앱을 배포 하는 동안 DefaultConnection 환경 변수의 값으로 키 값을 재정의할 수 있습니다. 환경 변수는 중요 한 자격 증명을 사용 하 여 전체 연결 문자열을 저장할 수 있습니다.

경고

환경 변수는 일반적으로 암호화 되지 않은 일반 텍스트로 저장 됩니다. 컴퓨터 또는 프로세스가 손상 되 면 신뢰할 수 없는 당사자가 환경 변수에 액세스할 수 있습니다. 사용자 비밀 공개를 방지 하는 추가 조치가 필요할 수 있습니다.

: 구분 기호는 모든 플랫폼의 환경 변수 계층적 키에서 작동하지 않습니다. 이중 밑줄 __은 다음과 같습니다.

  • 모든 플랫폼에서 지원됩니다. 예를 들어 : 구분 기호는 Bash에서 지원되지 않지만 __은 지원됩니다.
  • 자동으로 :으로 대체

비밀 관리자

암호 관리자 도구는 ASP.NET Core 프로젝트를 개발 하는 동안 중요 한 데이터를 저장 합니다. 이 컨텍스트에서 중요 한 데이터 조각은 앱 암호입니다. 앱 암호는 프로젝트 트리와는 별도의 위치에 저장 됩니다. 앱 암호는 특정 프로젝트에 연결 되거나 여러 프로젝트에서 공유 됩니다. 앱 비밀이 소스 제어에 체크 인 되지 않습니다.

경고

비밀 관리자 도구는 저장 된 비밀을 암호화 하지 않으며 신뢰할 수 있는 저장소로 처리 되어서는 안 됩니다. 개발 목적 으로만 사용 됩니다. 키와 값은 사용자 프로필 디렉터리의 JSON 구성 파일에 저장 됩니다.

비밀 관리자 도구의 작동 원리

비밀 관리자 도구는 값이 저장 되는 위치 및 방법과 같은 구현 세부 정보를 숨깁니다. 이러한 구현 세부 정보를 몰라도 도구를 사용할 수 있습니다. 값은 로컬 컴퓨터의 사용자 프로필 폴더에 있는 JSON 파일에 저장 됩니다.

파일 시스템 경로:

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

위의 파일 경로에서를 <user_secrets_id> UserSecretsId 프로젝트 파일에 지정 된 값으로 바꿉니다.

암호 관리자 도구를 사용 하 여 저장 된 데이터의 위치 또는 형식에 따라 달라 지는 코드를 작성 하지 마세요. 이러한 구현 세부 정보는 변경 될 수 있습니다. 예를 들어 비밀 값은 암호화 되지 않지만 나중에 있을 수 있습니다.

비밀 저장소 사용

비밀 관리자 도구는 사용자 프로필에 저장 된 프로젝트별 구성 설정에 대해 작동 합니다.

암호 관리자 도구는 init .NET Core SDK 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"

Visual Studio JSON 구조 평면화

Visual Studio의 사용자 비밀 관리 제스처는 텍스트 편집기에서 파일 에secrets.js 를 엽니다. secrets.js 의 내용을 저장할 키-값 쌍으로 바꿉니다. 예를 들어:

{
  "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 개체 리터럴이 축소 됩니다. 수정 된 파일은 다음 JSON과 유사 합니다.

{
  "Movies:ServiceApiKey": "12345"
}

여러 비밀 설정

암호 일괄 처리는 명령에 대해 파이프로 파이프 하 여 설정할 수 있습니다 set . 다음 예제에서는 파일의 내용 에 대 한input.js 를 명령으로 파이프 set 합니다.

명령 셸을 열고 다음 명령을 실행 합니다.

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

비밀 액세스

비밀에 액세스 하려면 다음 단계를 완료 합니다.

  1. 사용자 암호 구성 원본 등록
  2. 구성 API를 통해 암호를 읽습니다.

사용자 암호 구성 원본 등록

사용자 암호 구성 공급자 는 .NET 구성 API를 사용 하 여 적절 한 구성 소스를 등록 합니다.

사용자 암호 구성 소스는 프로젝트가를 호출할 때 개발 모드에서 자동으로 추가 됩니다 CreateDefaultBuilder . CreateDefaultBuilderAddUserSecrets가 인 경우를 호출 합니다 EnvironmentName 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를 통해 암호를 읽습니다.

사용자 암호 구성 원본이 등록 되어 있으면 .NET 구성 API에서 비밀을 읽을 수 있습니다. 생성자 주입 은 .NET 구성 API에 대 한 액세스 권한을 얻는 데 사용할 수 있습니다. 키를 읽는 다음 예제를 고려 합니다 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
    }
}

자세한 내용은 Razor 페이지의 시작 및 액세스 구성 에서 액세스 구성 을 참조 하세요.

POCO에 비밀 매핑

전체 개체 리터럴을 POCO (속성이 있는 간단한 .NET 클래스)에 매핑하면 관련 된 속성을 집계할 때 유용 합니다.

파일에 대한 앱의 secrets.js 다음 두 개의 비밀이 포함되어 있다고 가정합니다.

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

위의 비밀을 POCO에 매핑하려면 .NET 구성 API의 개체 그래프 바인딩 기능을 사용 합니다. 다음 코드는 사용자 지정 POCO에 바인딩하고 MovieSettings 속성 값에 액세스 합니다 ServiceApiKey .

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

Movies:ConnectionStringMovies: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 설정하여 연결 문자열을 완료할 수 있습니다.

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.js 다음 두 개의 비밀이 포함되어 있다고 가정합니다.

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

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets list

다음과 같은 출력이 표시됩니다.

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

앞의 예제에서 키 이름의 콜론은 에서 secrets.js 내의 개체 계층을 지정합니다.

단일 비밀 제거

파일에 대한 앱의 secrets.js 다음 두 개의 비밀이 포함되어 있다고 가정합니다.

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

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets remove "Movies:ConnectionString"

파일에 대한 앱의 secrets.js 키와 연결된 키-값 쌍을 제거하도록 수정되었습니다. MoviesConnectionString

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

dotnet user-secrets list 는 다음 메시지를 표시합니다.

Movies:ServiceApiKey = 12345

모든 비밀 제거

파일에 대한 앱의 secrets.js 다음 두 개의 비밀이 포함되어 있다고 가정합니다.

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

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets clear

앱의 모든 사용자 비밀이 파일의secrets.js 삭제되었습니다.

{}

dotnet user-secrets list 실행하여 다음 메시지가 표시됩니다.

No secrets configured for this application.

Visual Studio 통해 사용자 비밀 관리

Visual Studio 사용자 비밀을 관리하려면 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 사용자 비밀 관리를 선택합니다.

사용자 비밀 관리를 보여 Visual Studio

추가 리소스

By Rick Anderson, Daniel Rick및 Scott Addie

예제 코드 살펴보기 및 다운로드 (다운로드 방법)

이 문서에서는 개발 머신에서 ASP.NET Core 앱의 중요한 데이터를 관리하는 방법을 설명합니다. 암호 또는 기타 중요한 데이터를 소스 코드에 저장하지 마십시오. 프로덕션 비밀은 개발 또는 테스트에 사용하면 안 됩니다. 비밀을 앱과 함께 배포하면 안 됩니다. 대신 환경 변수 또는 Azure Key Vault 같은 제어된 수단을 통해 프로덕션 비밀에 액세스해야 합니다. Azure Key Vault 구성 제공자로 Azure 테스트 및 프로덕션 암호를 저장하고 보호할 수 있습니다.

환경 변수

환경 변수는 코드 또는 로컬 구성 파일에서 앱 비밀의 스토리지를 방지하는 데 사용됩니다. 환경 변수는 이전에 지정된 모든 구성 원본에 대한 구성 값을 재정의합니다.

개별 사용자 계정 보안이 사용되는 ASP.NET Core 웹앱을 고려해 보십시오. 기본 데이터베이스 연결 문자열은 키와 함께 프로젝트의 appsettings.json 파일에 포함됩니다. DefaultConnection 기본 연결 문자열은 사용자 모드에서 실행되며 암호가 필요하지 않은 LocalDB 위한 것입니다. 앱을 배포하는 동안 DefaultConnection 키 값은 환경 변수의 값으로 재정의할 수 있습니다. 환경 변수는 중요한 자격 증명을 사용하여 전체 연결 문자열을 저장할 수 있습니다.

경고

환경 변수는 일반적으로 암호화되지 않은 일반 텍스트로 저장됩니다. 컴퓨터 또는 프로세스가 손상된 경우 신뢰할 수 없는 당사자가 환경 변수에 액세스할 수 있습니다. 사용자 비밀 공개를 방지하기 위한 추가 조치가 필요할 수 있습니다.

: 구분 기호는 모든 플랫폼의 환경 변수 계층적 키에서 작동하지 않습니다. 이중 밑줄 __은 다음과 같습니다.

  • 모든 플랫폼에서 지원됩니다. 예를 들어 : 구분 기호는 Bash에서 지원되지 않지만 __은 지원됩니다.
  • 자동으로 :으로 대체

비밀 관리자

비밀 관리자 도구는 ASP.NET Core 프로젝트를 개발하면서 중요한 데이터를 저장합니다. 이 컨텍스트에서 중요한 데이터의 조각은 앱 비밀입니다. 앱 비밀은 프로젝트 트리와 별도의 위치에 저장됩니다. 앱 비밀은 특정 프로젝트와 연결되거나 여러 프로젝트에서 공유됩니다. 앱 비밀은 소스 제어에 체크 인되지 않습니다.

경고

비밀 관리자 도구는 저장된 비밀을 암호화하지 않으며 신뢰할 수 있는 저장소로 취급해서는 안 됩니다. 개발 목적으로만 사용됩니다. 키와 값은 사용자 프로필 디렉터리의 JSON 구성 파일에 저장됩니다.

비밀 관리자 도구의 작동 방식

비밀 관리자 도구는 값이 저장되는 위치 및 방법과 같은 구현 세부 정보를 숨깁니다. 이러한 구현 세부 정보를 모르고 도구를 사용할 수 있습니다. 값은 로컬 컴퓨터의 사용자 프로필 폴더에 있는 JSON 파일에 저장됩니다.

파일 시스템 경로:

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

위의 파일 경로에서 를 <user_secrets_id> 프로젝트 UserSecretsId 파일에 지정된 값으로 대체합니다.

비밀 관리자 도구를 사용하여 저장된 데이터의 위치 또는 형식에 따라 달라지는 코드를 작성하지 마세요. 이러한 구현 세부 정보는 변경 될 수 있습니다. 예를 들어 비밀 값은 암호화되지 않지만 나중에 암호화될 수 있습니다.

비밀 스토리지 사용

비밀 관리자 도구는 사용자 프로필에 저장된 프로젝트별 구성 설정에서 작동합니다.

사용자 비밀을 사용하려면 UserSecretsId 프로젝트 파일의 내에 요소를 PropertyGroup 정의합니다. 의 내부 UserSecretsId 텍스트는 임의적이지만 프로젝트에 고유합니다. 개발자는 일반적으로 에 대한 GUID를 UserSecretsId 생성합니다.

<PropertyGroup>
  <TargetFramework>netcoreapp2.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"

Visual Studio JSON 구조 평면화

Visual Studio 사용자 비밀 관리 제스처는 텍스트 편집기에서 파일에 대한secrets.js 엽니다. 의secrets.js 내용을 저장할 키-값 쌍으로 대체합니다. 예를 들어:

{
  "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 개체 리터럴이 축소됩니다. 수정된 파일은 다음 JSON과 유사합니다.

{
  "Movies:ServiceApiKey": "12345"
}

여러 비밀 설정

JSON을 명령에 파이핑하여 비밀 일괄 처리를 설정할 수 set 있습니다. 다음 예제에서는 파일 내용의 input.js set 명령으로 파이프됩니다.

명령 셸을 열고 다음 명령을 실행합니다.

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

비밀 액세스

구성 API는 사용자 비밀에 대한 액세스를 제공합니다.

프로젝트가 .NET Framework 대상으로 하는 경우 Microsoft.Extensions.Configuration을 설치합니다. UserSecrets NuGet 패키지.

ASP.NET Core 2.0 이상에서는 프로젝트에서 를 호출할 때 사용자 비밀 구성 원본이 개발 모드에서 자동으로 CreateDefaultBuilder 추가됩니다. CreateDefaultBuilderAddUserSecrets는 가 일 때 를 EnvironmentName 호출합니다. Development

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>();

CreateDefaultBuilder가 호출되지 않으면 생성자에서 를 호출하여 사용자 비밀 구성 원본을 명시적으로 AddUserSecrets Startup 추가합니다. AddUserSecrets다음 예제와 같이 앱이 개발 환경에서 실행되는 경우에만 를 호출합니다.

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", 
                     optional: false, 
                     reloadOnChange: true)
        .AddEnvironmentVariables();

    if (env.IsDevelopment())
    {
        builder.AddUserSecrets<Startup>();
    }

    Configuration = builder.Build();
}

.NET 구성 API를 통해 사용자 비밀을 검색할 수 있습니다.

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

POCO에 비밀 매핑

전체 개체 리터럴을 POCO(속성이 있는 간단한 .NET 클래스)에 매핑하는 것은 관련 속성을 집계하는 데 유용합니다.

파일에 대한 앱의 secrets.js 다음 두 개의 비밀이 포함되어 있다고 가정합니다.

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

위의 비밀을 POCO에 매핑하려면 .NET 구성 API의 개체 그래프 바인딩 기능을 사용합니다. 다음 코드는 사용자 지정 MovieSettings POCO에 바인딩하고 속성 값에 액세스합니다. ServiceApiKey

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

Movies:ConnectionStringMovies: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; $CREDENTIAL_PLACEHOLDER$;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 설정하여 연결 문자열을 완료할 수 있습니다.

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

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

비밀 나열

파일에 대한 앱의 secrets.js 다음 두 개의 비밀이 포함되어 있다고 가정합니다.

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

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets list

다음과 같은 출력이 표시됩니다.

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

앞의 예제에서 키 이름의 콜론은 에서 secrets.js 내의 개체 계층을 지정합니다.

단일 비밀 제거

파일에 대한 앱의 secrets.js 다음 두 개의 비밀이 포함되어 있다고 가정합니다.

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

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets remove "Movies:ConnectionString"

파일에 대한 앱의 secrets.js 키와 연결된 키-값 쌍을 제거하도록 수정되었습니다. MoviesConnectionString

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

dotnet user-secrets list 실행하여 다음 메시지가 표시됩니다.

Movies:ServiceApiKey = 12345

모든 비밀 제거

파일에 대한 앱의 secrets.js 다음 두 개의 비밀이 포함되어 있다고 가정합니다.

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

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets clear

앱의 모든 사용자 비밀이 파일의secrets.js 삭제되었습니다.

{}

dotnet user-secrets list 실행하여 다음 메시지가 표시됩니다.

No secrets configured for this application.

추가 자료