개발 중 민감한 응용 프로그램 정보 안전하게 저장하기
- 본 번역문서의 원문은 Safe storage of app secrets during development docs.microsoft.com 입니다.
본문에서는 개발 시 Secret Manager 도구를 이용해서 민감한 데이터를 코드 외부에 저장하는 방법을 살펴봅니다. 무엇보다 중요한 점은 절대로 소스 코드에 암호나 기타 민감한 데이터를 저장하면 안되며, 운영 환경의 보안 정보를 개발 및 테스트 모드에서 사용해서는 안된다는 것입니다. 대신, 구성 시스템을 이용해서 환경 변수로부터 또는 Secret Manager 도구를 이용해서 저장된 값들로부터 이런 값을 읽어올 수 있습니다. Secret Manager 도구는 민감한 보안 정보가 소스 제어에 체크인되지 않게끔 도와줍니다. 구성 시스템은 Secret Manager 도구를 이용해서 저장된 민감한 정보를 읽을 수 있습니다.
Secret Manager 도구는 개발 시에만 사용됩니다. Azure의 테스트 및 운영 보안 데이터는 Microsoft Azure Key Vault 구성 공급자를 이용해서 보호할 수 있습니다. 보다 자세한 정보는 Azure Key Vault configuration provider 문서를 참고하시기 바랍니다.
환경 변수
응용 프로그램의 보안 정보는 코드나 로컬 구성 파일보다는 환경 변수에 저장해야 합니다.
AddEnvironmentVariables
를 호출하면 환경 변수에서 값을 읽도록 구성 프레임워크를 설정할 수 있습니다.
그런 다음, 환경 변수를 사용해서 미리 지정된 모든 구성 소스의 구성 값을 재지정 할 수 있습니다.
가령, Visual Studio에서 개별 사용자 계정 옵션으로 새로운 ASP.NET Core 웹 응용 프로그램을 생성하면, 프로젝트의 appsettings.json 파일에 DefaultConnection
이라는 키를 가진 기본 연결 문자열이 추가됩니다.
이 기본 연결 문자열은 사용자 모드에서 실행되고 암호를 요구하지 않는 LocalDB를 사용하도록 구성되는데, 응용 프로그램을 테스트 서버나 운영 서버에 배포할 때, DefaultConnection
키의 값을 테스트 또는 프로덕션 데이터베이스 서버의 연결 문자열이 지정된 (민감한 자격 증명이 포함될 수 있는) 환경 변수 설정으로 재정의 할 수 있습니다.
경고
일반적으로 환경 변수는 평문으로 저장되며 암호화되지 않습니다. 머신이나 프로세스가 손상될 경우, 신뢰할 수 없는 사용자가 환경 변수에 접근할 수 있습니다. 따라서 여전히 사용자의 보안 정보 유출을 방지하기 위한 추가적인 방안이 필요할 수도 있습니다.
Secret Manager
Secret Manager 도구는 개발에 필요한 민감한 데이터를 프로젝트의 디렉터리 구조 외부에 저장합니다. Secret Manager 도구는 개발 기간 동안, .NET Core 프로젝트에 사용되는 보안 정보를 저장하기 위해서 사용할 수 있는 프로젝트 도구입니다. Secret Manager 도구를 사용하면, 응용 프로그램의 보안 정보를 특정 프로젝트와 연결하고 이를 여러 프로젝트에서 공유할 수 있습니다.
경고
Secret Manager 도구는 보안 정보를 암호화해서 저장하지 않기 때문에, 신뢰할 수 있는 저장소로 간주하면 안됩니다. 이 도구는 오로지 개발 목적으로만 사용해야 합니다. 키와 값은 사용자 프로파일 디렉터리에 위치한 JSON 구성 파일에 저장됩니다.
Visual Studio 2017: Secret Manager 도구 설치하기
마우스 오른쪽 버튼으로 솔루션 탐색기에서 프로젝트를 클릭한 다음, <project_name>.csproj 편집 (Edit <project_name>.csproj) 메뉴를 선택합니다. 다음에 강조된 라인을 .csproj 파일에 추가하고 저장하면 관련된 NuGet 패키지가 복원됩니다:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<UserSecretsId>My-USER-SECRET-ID-HERE-c23d27a4-eb88</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.1" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="1.0.0-msbuild3-final" />
</ItemGroup>
</Project>
다시 마우스 오른쪽 버튼으로 솔루션 탐색기에서 프로젝트를 클릭한 다음, 컨텍스트 메뉴에서 사용자 암호 관리 (Manage User Secrets) 메뉴를 선택합니다.
그러면 .csproj 파일의 PropertyGroup
노드 하위에 새로운 UserSecretsId
노드가 추가되고, secrets.json
파일이 편집기에서 열립니다.
다음과 같이 새로운 키와 값을 secrets.json
파일에 추가합니다:
{
"MySecret": "ValueOfMySecret"
}
Visual Studio 2015: Secret Manager 도구 설치하기
프로젝트의 project.json
파일을 엽니다.
그리고 tools
속성에 Microsoft.Extensions.SecretManager.Tools
참조를 추가하고 저장하면 관련된 NuGet 패키지가 복원됩니다:
"tools": {
"Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
마우스 오른쪽 버튼으로 솔루션 탐색기에서 프로젝트를 클릭한 다음, 컨텍스트 메뉴에서 사용자 암호 관리 (Manage User Secrets) 메뉴를 선택합니다.
그러면 project.json
파일에 새로운 userSecretsId
속성이 추가되고, 편집기에 secrets.json
파일이 열립니다.
다음과 같이 새로운 키와 값을 secrets.json
파일에 추가합니다:
{
"MySecret": "ValueOfMySecret"
}
Visual Studio Code 또는 명령 프롬프트: Secret Manager 도구 설치하기
프로젝트의 .csproj 파일에 Microsoft.Extensions.SecretManager.Tools
를 추가하고 dotnet restore
를 실행합니다.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<UserSecretsId>My-USER-SECRET-ID-HERE-c23d27a4-eb88</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.1" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="1.0.0-msbuild3-final" />
</ItemGroup>
</Project>
다음 명령을 실행하면 Secret Manager 도구를 테스트 할 수 있습니다:
dotnet user-secrets -h
그러면 Secret Manager 도구의 사용법, 옵션 및 명령 도움말이 표시됩니다.
노트
이와 같이 .csproj 파일의 DotNetCliToolReference
노드에 정의된 도구를 실행하려면 .csproj 파일과 동일한 디렉터리에 위치해 있어야 합니다.
Secret Manager 도구는 사용자 프로필에 저장된 프로젝트 별 구성 설정을 대상으로 동작합니다.
사용자 보안 정보를 사용하려면 프로젝트의 .csproj 파일에 UserSecretsId
값을 지정해야 합니다.
UserSecretsId
값은 임의적이긴 하지만 일반적으로 프로젝트에 고유해야 합니다.
개발자는 대부분 UserSecretsId
값에 GUID를 생성해서 지정합니다.
프로젝트의 .csproj 파일에 UserSecretsId
를 추가합니다:
<PropertyGroup>
<UserSecretsId>My-USER-SECRET-ID-HERE-c23d27a4-eb88</UserSecretsId>
</PropertyGroup>
그런 다음, Secret Manager 도구를 사용해서 보안 정보를 설정합니다. 이를테면 프로젝트 디렉터리의 명령 창에 다음과 같이 입력합니다:
dotnet user-secrets set MySecret ValueOfMySecret
다른 디렉터리에서 Secret Manager 도구를 실행할 수도 있지만, --project
옵션을 사용해서 .csproj 파일의 경로를 전달해야 합니다:
dotnet user-secrets set MySecret ValueOfMySecret --project c:\work\WebApp1\src\webapp1
Secret Manager 도구를 사용하면 응용 프로그램의 보안 정보의 목록을 조회하거나 제거하고 초기화시킬 수도 있습니다.
구성을 통해서 사용자 보안 정보에 접근하기
구성 시스템을 통해서 Secret Manager 도구를 이용해서 저장한 사용자 보안 정보에 접근할 수 있습니다.
먼저 프로젝트에 Microsoft.Extensions.Configuration.UserSecrets
패키지를 추가한 다음, dotnet restore
를 실행합니다.
그리고 Startup
클래스의 생성자에 사용자 보안 정보 구성 소스를 추가합니다:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace UserSecrets
{
public class Startup
{
string _testSecret = null;
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder();
if (env.IsDevelopment())
{
builder.AddUserSecrets<Startup>();
}
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
_testSecret = Configuration["MySecret"];
}
public void Configure(IApplicationBuilder app)
{
var result = string.IsNullOrEmpty(_testSecret) ? "Null" : "Not Null";
app.Run(async (context) =>
{
await context.Response.WriteAsync($"Secret is {result}");
});
}
}
}
그리고 나면 구성 API를 통해서 사용자 보안 정보에 접근할 수 있습니다:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace UserSecrets
{
public class Startup
{
string _testSecret = null;
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder();
if (env.IsDevelopment())
{
builder.AddUserSecrets<Startup>();
}
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
_testSecret = Configuration["MySecret"];
}
public void Configure(IApplicationBuilder app)
{
var result = string.IsNullOrEmpty(_testSecret) ? "Null" : "Not Null";
app.Run(async (context) =>
{
await context.Response.WriteAsync($"Secret is {result}");
});
}
}
}
Secret Manager 도구의 동작 방식
Secret Manager 도구는 값이 저장되는 위치 및 방법 같은 구현에 관한 세부적인 내용을 추상화시킵니다. 이런 세부적인 내용을 모르더라도 Secret Manager 도구를 사용하는데는 아무 지장도 없습니다. 현재 버전에서는 사용자 프로필 디렉터리의 JSON 구성 파일에 값이 저장됩니다:
-
Windows:
%APPDATA%\microsoft\UserSecrets\<userSecretsId>\secrets.json
-
Linux:
~/.microsoft/usersecrets/<userSecretsId>/secrets.json
-
Mac:
~/.microsoft/usersecrets/<userSecretsId>/secrets.json
여기서 <userSecretsId>
의 값은 .csproj 파일에 지정된 값입니다.
그러나 Secret Manager 도구로 저장한 데이터의 경로나 형식에 의존해서 코드를 작성하면 안됩니다. 이런 세부적인 구현 사항은 변경될 수 있기 때문입니다. 예를 들어서, 지금은 보안 정보가 암호화되지 않지만 나중에는 암호화 될 수도 있습니다.
추가 자료
- 권한부여: 개요 2017-01-14 08:00
- 권한부여: 간단한 권한부여 2017-01-14 11:00
- 권한부여: 역할 기반 권한부여 2017-01-14 14:00
- 권한부여: 클레임 기반 권한부여 2017-01-15 08:00
- 권한부여: 사용자 지정 정책 기반 권한부여 2017-01-15 11:00
- 권한부여: 요구사항 처리기와 의존성 주입 2017-01-15 14:00
- 권한부여: 리소스 기반 권한부여 2017-01-16 08:00
- 권한부여: 뷰 기반 권한부여 2017-01-16 11:00
- 권한부여: 스키마별 신원 제한 2017-01-16 14:00
- 인증: ASP.NET Core Identity 살펴보기 2017-01-30 08:00
- 인증: Facebook, Google 및 기타 외부 공급자를 이용한 인증 활성화시키기 2017-02-13 08:00
- 인증: Facebook 인증 구성하기 2017-02-13 11:00
- 인증: Twitter 인증 구성하기 2017-02-20 08:00
- 인증: Google 인증 구성하기 2017-02-20 11:00
- 인증: Microsoft 계정 인증 구성하기 2017-02-20 14:00
- 인증: 계정 확인 및 비밀번호 복구 2017-03-06 08:00
- 인증: SMS를 이용한 2단계 인증 2017-03-13 08:00
- 인증: ASP.NET Core Identity 없이 Cookie 미들웨어 사용하기 2017-03-20 08:00
- 데이터 보호: 데이터 보호 개요 2017-03-27 08:00
- 데이터 보호: 데이터 보호 API 시작하기 2017-03-29 08:00
- 데이터 보호: 소비자 APIs 개요 2017-03-31 08:00
- 데이터 보호: 용도 문자열 2017-04-03 08:00
- 데이터 보호: ASP.NET Core의 용도 계층 구조 및 다중-테넌트(Multi-Tenancy) 2017-04-05 08:00
- 데이터 보호: 비밀번호 해싱 2017-04-07 08:00
- 데이터 보호: 보호된 페이로드의 수명 제한하기 2017-04-10 08:00
- 테이터 보호: 키가 취소된 페이로드의 보호 해제하기 2017-04-12 08:00
- 데이터 보호: 데이터 보호 구성하기 2017-04-14 08:00
- 데이터 보호: 키 관리 및 수명 기본 설정 2017-04-17 08:00
- 데이터 보호: 머신 수준 정책 2017-04-19 08:00
- 데이터 보호: 비-DI 인식 시나리오 2017-04-21 08:00
- 호환성: 응용 프로그램 간 인증 쿠키 공유하기 2017-05-12 08:00
- 호환성: ASP.NET의 <machineKey> 요소 대체하기 2017-05-16 08:00
- 교차 원본 요청 활성화시키기 (CORS) 2017-05-17 08:00
- ASP.NET Core 응용 프로그램에 SSL 적용하기 2017-05-18 08:00
- 개발 중 민감한 응용 프로그램 정보 안전하게 저장하기 2017-05-19 08:00