데이터 보호 시스템은 초기화되면 운영 환경에 따라 기본 설정을 적용합니다. 이러한 설정은 단일 컴퓨터에서 실행되는 앱에 적합합니다. 그러나 개발자가 기본 설정을 변경해야 하는 경우가 있습니다.
- 앱이 여러 머신에 분산되어 있습니다.
- 준수 이유로.
데이터 보호 시스템은 이러한 시나리오를 위한 여러 구성 API를 제공합니다.
Warning
데이터 보호 키 링은 구성 파일과 마찬가지로 적절한 권한을 사용하여 보호해야 합니다. 사용하지 않는 키를 암호화하도록 선택할 수 있지만, 이는 사이버 공격자가 새 키를 만드는 것을 방지하지는 않습니다. 따라서 앱의 보안이 영향을 받게 됩니다. 데이터 보호로 구성된 스토리지 위치는 구성 파일을 보호하는 방식과 비슷하게 앱 자체에 대한 액세스 권한이 제한되어야 합니다. 예를 들어, 키 링을 디스크에 저장하는 경우에는 파일 시스템 권한을 사용하세요. 웹앱이 실행되는 ID만 해당 디렉터리에 대한 읽기, 쓰기 및 만들기 액세스 권한이 있는지 확인합니다. Azure Blob Storage를 사용하는 경우, 웹앱만 Blob 저장소의 항목을 읽고, 쓰고, 만들 수 있어야 합니다.
확장 메서드 AddDataProtection는 IDataProtectionBuilder를 반환합니다.
IDataProtectionBuilder는 함께 연결하여 데이터 보호 옵션을 구성할 수 있는 확장 메서드를 노출합니다.
Note
이 문서는 Docker 컨테이너 내에서 실행되는 앱에 대해 작성되었습니다. Docker 컨테이너에서 앱의 경로는 항상 같으므로 동일한 애플리케이션 판별자입니다. 여러 환경(예: 로컬 및 배포됨)에서 실행해야 하는 앱은 환경에 대한 기본 애플리케이션 판별자를 설정해야 합니다. 여러 환경에서 앱을 실행하는 것은 이 문서의 범위를 벗어납니다.
이 문서에서 사용하는 데이터 보호 확장에는 다음과 같은 NuGet 패키지가 필요합니다.
Azure Key Vault를 사용하여 키 보호(ProtectKeysWithAzureKeyVault)
개발자 자격 증명을 사용하여 Azure Key Vault 와 로컬로 상호 작용하려면 Visual Studio에서 스토리지 계정에 로그인하거나 Azure CLI로 로그인합니다. Azure CLI를 아직 설치하지 않은 경우 Azure CLI를 설치하는 방법을 참조하세요. Visual Studio를 사용하지 않는 경우 Visual Studio의 개발자 PowerShell 패널 또는 명령 셸에서 다음 명령을 실행할 수 있습니다.
az login
자세한 내용은 개발자 도구를 사용하여 Azure에 로그인을 참조하세요.
Entra 또는 Azure 포털에서 키 저장소를 설정할 때 경우:
Azure 역할 기반 액세스 제어(RABC)를 사용하도록 키 자격 증명 모음을 구성합니다. 로컬 개발 및 테스트를 포함하여 Azure Virtual Network에서 작동하지 않는 경우 네트워킹 단계에서 공용 액세스가 사용하도록 설정되어 있는지 확인합니다(선택됨). 공용 액세스를 사용하도록 설정하면 키 자격 증명 모음 엔드포인트만 노출됩니다. 인증된 계정은 여전히 액세스에 필요합니다.
Azure Managed Identity를 만들거나 사용하는 기존 Managed Identity에 Key Vault Crypto 사용자 역할을 추가합니다. 배포를 호스팅하는 Azure App Service에 Managed Identity 를 할당합니다.사용자가 할당한>Identity>>추가입니다.
Note
Azure CLI 또는 Visual Studio의 Azure 서비스 인증을 사용하여 Blob 액세스를 위해 권한 있는 사용자와 함께 로컬로 앱을 실행하려는 경우 Key Vault Crypto 사용자 역할을 사용하여 IAM(Access Control)에 개발자 Azure 사용자 계정을 추가합니다. Visual Studio를 통해 Azure CLI를 사용하려면 개발자 PowerShell 패널에서 명령을 실행하고
az login프롬프트에 따라 테넌트에 인증합니다.키 암호화가 활성화된 경우 키 파일의 키에는 "This key is encrypted with Azure Key Vault." 주석이 포함됩니다. 앱을 시작한 후 키 행 끝에 있는 상황에 맞는 메뉴에서 보기/편집 명령을 선택하여 키에 키 자격 증명 모음 보안이 적용되어 있는지 확인합니다.
필요에 따라 만료/회전된 키 자격 증명 모음 키를 기반으로 데이터 보호 키를 사용하여 페이로드의 암호를 해독하는 것에 대한 우려 없이 자동 키 자격 증명 모음 키 회전을 사용하도록 설정할 수 있습니다. 생성된 각 데이터 보호 키에는 암호화하는 데 사용되는 키 자격 증명 모음 키에 대한 참조가 포함됩니다. 만료된 키 볼트 키를 보관하고, 키 볼트에서 삭제하지 마세요. 또한 앱의 키 자격 증명 모음 구성에서 버전 없는 키 식별자를 사용합니다. 여기서는 식별자 끝에 키 GUID가 배치되지 않습니다(예:
https://contoso.vault.azure.net/keys/data-protection). 데이터 보호 키 회전 시 새 키 자격 증명 모음 키가 사용되도록 키 자격 증명 모음 키가 데이터 보호 키보다 더 자주 회전하는 두 키에 대해 비슷한 회전 기간을 사용합니다.
Azure Key Vault로 키를 보호하면 키 링 스토리지 위치를 비롯한 자동 데이터 보호 설정이 비활성화됩니다. Blob Storage에 키를 저장하도록 Azure Blob Storage 공급자를 구성하려면 ASP.NET Core의 키 스토리지 공급자에 대한 지침을 따르고 앱의 오버로드 중 PersistKeysToAzureBlobStorage 하나를 호출합니다. 다음 예제에서는 RBAC(역할 기반 액세스 제어)를 위해 Azure Managed TokenCredential 를 사용하여 Blob URI 및 토큰 자격 증명(Identity)을 허용하는 오버로드를 사용합니다.
Azure Key Vault 공급자를 구성하려면 오버로드 중 ProtectKeysWithAzureKeyVault 하나를 호출합니다. 다음 예제에서는 키 식별자 및 토큰 자격 증명(TokenCredential)을 허용하는 오버로드를 사용하고, 프로덕션 중 RBAC는 Managed Identity에 의존하며, 개발 및 테스트에서는 ManagedIdentityCredential에 의존합니다. 다른 오버로드는 키 볼트 클라이언트 또는 클라이언트 비밀이 있는 앱 클라이언트 ID를 허용합니다. 자세한 내용은 ASP.NET Core의 키 스토리지 공급자를 참조하세요.
Azure SDK의 API 및 인증에 대한 자세한 내용은 Azure 라이브러리를 사용하여 Azure 서비스에 .NET 앱 인증 및 Azure Identity역할 기반 액세스 제어를 사용하여 Key Vault 키, 인증서 및 비밀에 대한 액세스 제공을 참조하세요. 로깅 지침은 Azure SDK for .NET: 클라이언트 등록 없이 로깅하기을 참조하세요. 종속성 주입을 사용하는 앱의 경우, 앱은 로그 인프라를 생성하고 연결하기 위해 AddAzureClientsCore를 true로 전달하여 enableLogForwarding를 호출할 수 있습니다.
Azure Portal에서 키를 만들려면 빠른 시작: Azure Portal을 사용하여 Azure Key Vault에서 키 설정 및 검색을 참조하세요. 키에 최소한 Get, Unwrap Key및 Wrap Key 사용 권한을 부여합니다. 앱의 구성에 사용할 키 식별자를 기록합니다. 키 자격 증명 모음 키의 자동 회전을 사용하도록 설정하려는 경우 식별자 끝에 키 GUID가 배치되지 않는 버전 없는 키 식별자를 기록합니다(예: https://contoso.vault.azure.net/keys/data-protection).
Program 서비스가 등록된 파일에서:
TokenCredential? credential;
if (builder.Environment.IsProduction())
{
credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
// Local development and testing only
DefaultAzureCredentialOptions options = new()
{
// Specify the tenant ID to use the dev credentials when running the app locally
// in Visual Studio.
VisualStudioTenantId = "{TENANT ID}",
SharedTokenCacheTenantId = "{TENANT ID}"
};
credential = new DefaultAzureCredential(options);
}
builder.Services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}: Azure 관리형 Identity 클라이언트 ID(GUID).
{TENANT ID}: 테넌트 ID입니다.
{APPLICATION NAME}: SetApplicationName 데이터 보호 시스템 내에서 이 앱의 고유한 이름을 설정합니다. 값은 앱 배포에서 일치해야 합니다.
{BLOB URI}: 키 파일에 대한 전체 URI입니다. URI는 키 파일을 만들 때 Azure Storage에서 생성됩니다. SAS를 사용하지 마세요.
{KEY IDENTIFIER}: 키 암호화에 사용되는 Azure Key Vault 키 식별자입니다. 액세스 정책을 사용하면 애플리케이션이 Get, Unwrap Key, 및 Wrap Key 사용 권한으로 키 자격 증명 보관소에 액세스할 수 있습니다. 키의 버전은 생성된 후 Entra 또는 Azure Portal의 키에서 가져옵니다. 키 자격 증명 모음 키의 자동 회전을 사용하도록 설정하는 경우 앱의 키 자격 증명 모음 구성에서 버전 없는 키 식별자를 사용해야 합니다. 여기서 키 GUID는 식별자 끝에 배치되지 않습니다(예: https://contoso.vault.azure.net/keys/data-protection).
앱이 Azure Key Vault와 통신하고 권한을 부여하려면 앱에서 Azure.Identity NuGet 패키지를 참조해야 합니다.
Note
.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 작업 흐름(NuGet 문서)의 패키지 설치 및 관리 섹션에서 확인할 수 있습니다. 올바른 패키지 버전을 NuGet.org에서 확인하세요.
Note
비-Production환경에서는 인증을 간소화하기 위해 Azure 호스팅 환경에서 사용되는 자격 증명과 로컬 개발에 사용되는 자격 증명을 결합하여 Azure에 배포하는 앱을 개발하는 동안 이전 예제에서는 DefaultAzureCredential을 사용합니다. 자세한 내용은 시스템 할당 관리 ID를 사용하여 Azure 리소스에 Azure 호스팅 .NET 앱 인증을 참조하세요.
앱에서 이전 Azure 패키지(Microsoft.AspNetCore.DataProtection.AzureStorage 및 Microsoft.AspNetCore.DataProtection.AzureKeyVault)를 사용하는 경우, 이러한 참조를 제거하고Azure.Extensions.AspNetCore.DataProtection.Blobs 및 Azure.Extensions.AspNetCore.DataProtection.Keys 패키지로 업그레이드하는 것을 권장합니다. 최신 패키지는 주요 보안 및 안정성 문제를 해결합니다.
대체 SAS(공유 액세스 서명) 접근 방식: Azure Blob Storage의 키 Blob에 액세스하기 위해 Managed Identity 를 사용하는 대신 SAS 토큰으로 Blob URI를 허용하는 오버로드를 호출 PersistKeysToAzureBlobStorage 할 수 있습니다. 다음 예제에서는 앞의 예제와 같이 ManagedIdentityCredential (프로덕션) 또는 DefaultAzureCredential (개발 및 테스트) TokenCredential를 계속 사용합니다.
builder.Services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{APPLICATION NAME}: SetApplicationName 데이터 보호 시스템 내에서 이 앱의 고유한 이름을 설정합니다. 값은 앱 배포에서 일치해야 합니다.
{BLOB URI WITH SAS}: 키 파일을 SAS 토큰과 함께 쿼리 문자열 매개 변수로 저장해야 하는 전체 URI입니다. 업로드된 키 파일에 대한 SAS를 요청할 때 Azure Storage에서 URI를 생성합니다.
{KEY IDENTIFIER}: 키 암호화에 사용되는 Azure Key Vault 키 식별자입니다. 액세스 정책을 사용하면 애플리케이션이 Get, Unwrap Key, 및 Wrap Key 사용 권한으로 키 자격 증명 보관소에 액세스할 수 있습니다. 키의 버전은 생성된 후 Entra 또는 Azure Portal의 키에서 가져옵니다. 키 자격 증명 모음 키의 자동 회전을 사용하도록 설정하는 경우 앱의 키 자격 증명 모음 구성에서 버전 없는 키 식별자를 사용해야 합니다. 여기서 키 GUID는 식별자 끝에 배치되지 않습니다(예: https://contoso.vault.azure.net/keys/data-protection).
파일 시스템에 키 유지(PersistKeysToFileSystem)
%LOCALAPPDATA% 기본 위치 대신 UNC 공유 경로에 키를 저장하려면, PersistKeysToFileSystem을 사용하여 시스템을 구성하십시오.
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
Warning
키 지속성 위치를 변경하면 DPAPI가 적절한 암호화 메커니즘인지 여부를 알 수 없으므로 시스템에서 더 이상 미사용 키를 자동으로 암호화하지 않습니다.
데이터베이스에 키 유지(PersistKeysToDbContext)
EntityFramework를 사용하는 데이터베이스에 키를 저장하려면 Microsoft.AspNetCore.DataProtection.EntityFrameworkCore 패키지를 사용하여 시스템을 구성합니다.
builder.Services.AddDataProtection()
.PersistKeysToDbContext<SampleDbContext>();
위 코드는 구성된 데이터베이스에 키를 저장합니다. 사용되는 데이터베이스 컨텍스트는 IDataProtectionKeyContext를 구현해야 합니다.
IDataProtectionKeyContext는 DataProtectionKeys 속성을 노출합니다.
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
이 속성은 키가 저장되는 테이블을 나타냅니다. 테이블을 수동으로 또는 DbContext 마이그레이션을 사용하여 만듭니다. 자세한 내용은 DataProtectionKey를 참조하세요.
키 보호 구성 API(ProtectKeysWith\*)
시스템을 미사용 상태의 키를 보호하도록 구성하려면 ProtectKeysWith\* 구성 API 중 하나를 호출할 수 있습니다. UNC 공유에 키를 저장하고 특정 X.509 인증서를 사용하여 미사용 키를 암호화하는 아래 예제를 살펴보세요.
파일에서 X509Certificate2를 ProtectKeysWithCertificate에 제공하려면 X509CertificateLoader.LoadCertificateFromFile를 호출할 수 있습니다.
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));
다음 코드 예제에서는 지문을 사용하여 인증서를 로드하는 방법을 보여 줍니다.
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);
파일에서 로드된 인증서와 같이 X509Certificate2에 ProtectKeysWithCertificate를 제공할 수 있습니다.
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]));
다음 코드 예제에서는 지문을 사용하여 인증서를 로드하는 방법을 보여 줍니다.
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(builder.Configuration["CertificateThumbprint"]);
기본 제공 키 암호화 메커니즘에 대한 예제 및 논의는 ASP.NET Core를 사용하여 Windows 및 Azure의 미사용 키 암호화를 참조하세요.
인증서를 사용하여 키 보호 해제(UnprotectKeysWithAnyCertificate)
X509Certificate2인 UnprotectKeysWithAnyCertificate 인증서 배열을 사용하여 인증서를 교체하고 정지 상태의 키를 복호화할 수 있습니다.
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", builder.Configuration["CertificatePassword"]))
.UnprotectKeysWithAnyCertificate(
new X509Certificate2("certificate_1.pfx", builder.Configuration["CertificatePassword_1"]),
new X509Certificate2("certificate_2.pfx", builder.Configuration["CertificatePassword_2"]));
기본 키 수명 설정(SetDefaultKeyLifetime)
기본 90일 대신 14일의 키 수명을 사용하도록 시스템을 구성하려면 다음을 사용합니다 SetDefaultKeyLifetime.
builder.Services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
애플리케이션 이름 설정(SetApplicationName)
기본적으로 데이터 보호 시스템은 앱들 간에 동일한 물리적 키 리포지토리를 공유하는 경우에도 콘텐츠 루트 경로를 기반으로 앱을 서로 격리합니다. 이러한 격리에 따라 앱이 다른 앱의 보호된 페이로드를 알 수 없게 됩니다.
앱 간에 보호된 페이로드를 공유하려면:
- 각 앱에서 SetApplicationName을 같은 값으로 구성합니다.
- 각 앱에서 동일한 버전의 데이터 보호 API 스택을 사용합니다. 앱의 프로젝트 파일에서 다음 중 하나를 수행합니다.
- Microsoft.AspNetCore.App metapackage를 통해 동일한 공유 프레임워크 버전을 참조합니다.
- 동일한 데이터 보호 패키지 버전을 참조합니다.
builder.Services.AddDataProtection()
.SetApplicationName("<sharedApplicationName>");
SetApplicationName이 DataProtectionOptions.ApplicationDiscriminator를 내부적으로 설정합니다. 문제 해결을 위해 프레임워크에 의해 판별자에 할당된 값은 WebApplication이 Program.cs에 빌드된 후 배치된 다음 코드로 기록할 수 있습니다.
var discriminator = app.Services.GetRequiredService<IOptions<DataProtectionOptions>>()
.Value.ApplicationDiscriminator;
app.Logger.LogInformation("ApplicationDiscriminator: {ApplicationDiscriminator}", discriminator);
판별자가 사용되는 방법에 대한 자세한 내용은 이 문서의 뒷부분에 나오는 다음 섹션을 참조하세요.
Warning
.NET 6에서는 WebApplicationBuilder가 콘텐츠 루트 경로를 정규화하여 DirectorySeparatorChar로 끝납니다. 예를 들어 Windows에서 콘텐츠 루트 경로가 \로 끝나고 Linux에서는 /로 끝납니다. 다른 호스트는 경로를 정규화하지 않습니다.
HostBuilder 또는 WebHostBuilder에서 마이그레이션하는 대부분의 앱은 종료 DirectorySeparatorChar가 없으므로 동일한 앱 이름을 공유하지 않습니다. 이 문제를 해결하려면 다음 코드와 같이 디렉터리 구분 기호 문자를 제거하고 앱 이름을 수동으로 설정합니다.
using System.Reflection;
using Microsoft.AspNetCore.DataProtection;
var builder = WebApplication.CreateBuilder(args);
var trimmedContentRootPath =
builder.Environment.ContentRootPath.TrimEnd(Path.DirectorySeparatorChar);
builder.Services.AddDataProtection().SetApplicationName(trimmedContentRootPath);
var app = builder.Build();
app.MapGet("/", () => Assembly.GetEntryAssembly()!.GetName().Name);
app.Run();
자동 키 생성 사용 안 함(DisableAutomaticKeyGeneration)
키의 만료가 가까워지면 앱이 자동으로 키를 롤링(새 키 만들기)하지 못하도록 해야 하는 시나리오가 있을 수 있습니다. 이 시나리오의 한 가지 예로 기본/보조 관계로 설정된 앱을 들 수 있습니다. 여기서 기본 앱은 키 관리 문제를 담당하고, 보조 앱은 키 링에 대한 읽기 전용 보기만 가능합니다. 보조 앱은 DisableAutomaticKeyGeneration을 사용하여 시스템을 구성함으로써 키 링을 읽기 전용으로 취급하도록 구성할 수 있습니다.
builder.Services.AddDataProtection()
.DisableAutomaticKeyGeneration();
애플리케이션별 격리
데이터 보호 시스템이 ASP.NET Core 호스트에 의해 제공되는 경우, 앱이 동일한 작업자 프로세스 계정에서 실행되고 동일한 마스터 키 링 자료를 사용하는 경우에도 자동으로 앱을 서로 격리합니다. 이는 System.Web의 <machineKey> 요소의 IsolateApps 한정자와 비슷합니다.
격리 메커니즘은 로컬 컴퓨터에 있는 각 앱을 고유한 테넌트로 간주하는 방식으로 작동합니다. 따라서 지정된 앱에 대해 루트된 IDataProtector에는 자동으로 앱 ID가 판별자(ApplicationDiscriminator)로 포함됩니다. 앱의 고유 ID는 앱의 실제 경로입니다.
- IIS에 호스트되는 앱의 경우, 고유 ID는 앱의 IIS 실제 경로입니다. 앱이 웹 팜 환경에 배포된 경우, 웹 팜에 있는 모든 머신에서 IIS 환경이 비슷하게 구성되었다는 가정하에 이 값은 일정합니다.
- Kestrel 서버에서 실행되는 자체 호스트 앱의 경우, 고유 ID는 디스크에 있는 앱의 실제 경로입니다.
고유 식별자는 재설정-개별 앱과 컴퓨터 자체의 재설정-이 이루어져도 지속되도록 설계되었습니다.
이 격리 메커니즘에서는 앱이 악성이 아니라고 가정합니다. 악성 앱은 동일한 작업자 프로세스 계정에서 실행되는 다른 앱에 언제든지 영향을 줄 수 있습니다. 앱이 상호 신뢰하지 않는 공유 호스트 환경에서는 호스트 공급자가 앱의 기본 키 리포지토리를 분리하는 등 앱 간에 OS 수준 격리를 유지하기 위한 조치를 취해야 합니다.
데이터 보호 시스템이 ASP.NET Core 호스트에 의해 제공되지 않은 경우(예를 들어, DataProtectionProvider 구체적인 형식을 통해 인스턴스화한 경우), 앱 격리가 기본적으로 사용하지 않도록 설정됩니다. 앱 격리가 사용하지 않도록 설정되면, 동일한 키 링 자료를 사용하는 모든 앱은 적절한 용도를 제공하는 한 페이로드를 공유할 수 있습니다. 이 환경에서 앱 격리를 제공하려면 구성 개체에서 SetApplicationName 메서드를 호출하고 각 앱에 고유한 이름을 제공합니다.
데이터 보호와 앱 격리
앱 격리 시 다음을 고려해야 합니다.
여러 앱이 동일한 키 리포지토리를 가리킨다면 그 의도는 앱이 동일한 마스터 키 자료를 공유하도록 하는 것입니다. 데이터 보호는 키 링을 공유하는 모든 앱이 해당 키 링에 있는 모든 항목에 액세스할 수 있다는 가정하에 개발됩니다. 애플리케이션 고유 식별자는 키 링이 제공하는 키에서 파생된 애플리케이션별 키를 격리하는 데 사용됩니다. 추가 격리를 적용하기 위해 Azure KeyVault가 제공하는 것과 같은 항목 수준 권한은 필요하지 않습니다. 항목 수준 권한을 시도하면 애플리케이션 오류가 발생합니다. 기본 제공 애플리케이션 격리를 사용하지 않으려면 개별적인 키 저장소 위치를 사용해야 하며 애플리케이션 간에 공유되지 않아야 합니다.
애플리케이션 판별자(ApplicationDiscriminator)는 여러 앱이 동일한 마스터 키 재질을 공유하도록 하되 암호화 페이로드는 서로 구분하는 용도로 사용됩니다. 앱이 다른 앱의 암호화 페이로드를 읽을 수 있으려면 동일한 애플리케이션 판별자를 가져야 합니다. 동일한 애플리케이션 판별자는
SetApplicationName을 호출하여 설정할 수 있습니다.앱이 손상된 경우(예: RCE 공격에 의해) 해당 앱에 액세스할 수 있는 모든 마스터 키 자료도 보호 상태와 관계없이 손상된 것으로 간주되어야 합니다. 이는 두 앱이 동일한 리포지토리를 가리키는 경우, 서로 다른 앱 판별자를 사용하는 경우에도 하나의 앱의 손상되면 두 앱이 모두 손상된 것과 기능적으로 동일함을 의미합니다.
이 "두 모두에 대한 타협과 기능적으로 동일한" 조항은 두 앱이 비활성 상태에서 키를 보호하기 위해 각각 다른 메커니즘을 사용하는 경우에도 적용됩니다. 이는 일반적으로 사용되는 구성이 아닙니다. 미사용 보호 메커니즘은 사이버 공격이 리포지토리에 대한 읽기 액세스 권한을 얻는 경우 보호를 제공하기 위한 것입니다. 리포지토리에 대한 쓰기 액세스 권한을 얻는 사이버 공격(앱 내에서 코드 실행 권한을 획득했기 때문일 수 있습니다)은 스토리지에 악성 키를 삽입할 수 있습니다. 데이터 보호 시스템은 의도적으로 키 리포지토리에 대한 쓰기 액세스 권한을 얻는 사이버 공격자에 대한 보호를 제공하지 않습니다.
앱이 다른 앱과 진정으로 격리된 상태로 유지되려면 서로 다른 키 리포지토리를 사용해야 합니다. 이는 자연스럽게 “격리된”에 대한 정의를 벗어나게 됩니다. 다른 앱의 데이터 저장소에 대한 읽기 및 쓰기 권한을 갖는 앱은 격리되지 않습니다.
UseCryptographicAlgorithms을 사용하여 알고리즘을 변경하기
데이터 보호 스택을 통해 새로 생성된 키에서 사용하는 기본 알고리즘을 변경할 수 있습니다. 이 작업을 수행하는 가장 간단한 방법은 구성 콜백에서 호출 UseCryptographicAlgorithms 하는 것입니다.
builder.Services.AddDataProtection()
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
기본 EncryptionAlgorithm은 AES-256-CBC이고, 기본 ValidationAlgorithm은 HMACSHA256입니다. 기본 정책은 시스템 관리자가 설정하거나 머신 전체에 적용되는 정책을 통해 설정할 수 있으며, UseCryptographicAlgorithms를 명시적으로 호출하면 기본 정책이 재정의됩니다.
UseCryptographicAlgorithms를 호출하면 미리 정의된 기본 제공 목록에서 원하는 알고리즘을 지정할 수 있습니다. 알고리즘의 구현에 대해서는 신경 쓸 필요가 없습니다. 위 시나리오에서 데이터 보호 시스템은 Windows에서 실행되는 경우 AES의 CNG 구현을 사용하려고 시도합니다. 그렇지 않으면 관리 System.Security.Cryptography.Aes 되는 클래스로 돌아갑니다.
호출 UseCustomCryptographicAlgorithms을 통해 구현을 수동으로 지정할 수 있습니다.
Tip
알고리즘을 변경해도 키 링에 있는 기존 키는 영향을 받지 않습니다. 새로 생성되는 키만 영향을 받습니다.
사용자 지정 관리형 알고리즘 지정
사용자 지정 관리 알고리즘을 지정하려면 구현 형식을 ManagedAuthenticatedEncryptorConfiguration 가리키는 인스턴스를 만듭니다.
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new ManagedAuthenticatedEncryptorConfiguration
{
// A type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// A type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
일반적으로 *Type 속성은 매개 변수 없는 퍼블릭 ctor를 통해 구체적이고 인스턴스화 가능한 SymmetricAlgorithm 및 KeyedHashAlgorithm의 구현을 가리켜야 합니다. 단, 시스템에서 편의를 위해 특수 사례로 취급하는 typeof(Aes)와 같은 값도 있습니다.
Note
SymmetricAlgorithm은 키 길이가 128비트 이상이고 블록 크기가 64비트 이상이어야 하며, PKCS #7 패딩을 사용하여 CBC 모드 암호화를 지원해야 합니다. KeyedHashAlgorithm은 다이제스트 크기가 >=128비트(128비트 이상)이어야 하며, 해시 알고리즘의 다이제스트 길이와 동일한 길이의 키를 지원해야 합니다. KeyedHashAlgorithm은 반드시 HMAC여야 할 필요는 없습니다.
사용자 지정 Windows CNG 알고리즘 지정
HMAC 유효성 검사와 함께 CBC 모드 암호화를 사용하여 사용자 지정 Windows CNG 알고리즘을 CngCbcAuthenticatedEncryptorConfiguration 지정하려면 알고리즘 정보를 포함하는 인스턴스를 만듭니다.
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngCbcAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// Passed to BCryptOpenAlgorithmProvider
HashAlgorithm = "SHA256",
HashAlgorithmProvider = null
});
Note
대칭 블록 암호 알고리즘은 키 길이가 >= 128비트(128비트 이상)이고 블록 크기가 >= 64비트(64비트 이상)이어야 하며, PKCS #7 패딩을 사용하여 CBC 모드 암호화를 지원해야 합니다. 해시 알고리즘은 다이제스트 크기가 >= 128비트 이상이어야 하며, BCRYPT_ALG_HANDLE_HMAC_FLAG 플래그를 사용하여 열 수 있어야 합니다. *Provider 속성을 null로 설정하면 지정된 알고리즘에 대해 기본 공급자를 사용할 수 있습니다. 자세한 내용은 BCryptOpenAlgorithmProvider 설명서를 참조하세요.
Galois/카운터 모드 암호화와 유효성 검사를 사용하여 사용자 지정 Windows CNG 알고리즘을 지정하려면, 알고리즘 정보가 포함된 CngGcmAuthenticatedEncryptorConfiguration 인스턴스를 만드십시오.
builder.Services.AddDataProtection()
.UseCustomCryptographicAlgorithms(new CngGcmAuthenticatedEncryptorConfiguration
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
Note
대칭 블록 암호 알고리즘은 키 길이가 >= 128비트(128비트 이상)이고 블록 크기가 정확히 128비트이어야 하며 GCM 암호화를 지원해야 합니다. 지정된 알고리즘에 EncryptionAlgorithmProvider 기본 공급자를 사용하도록 속성을 null로 설정할 수 있습니다. 자세한 내용은 BCryptOpenAlgorithmProvider 설명서를 참조하세요.
그 밖의 사용자 지정 알고리즘 지정
데이터 보호 시스템은 1급 API로 노출되지 않지만, 거의 모든 종류의 알고리즘을 지정할 수 있을 만큼 확장성이 뛰어납니다. 예를 들어, 하나의 HSM(하드웨어 보안 모듈) 내에 포함된 모든 키를 유지하고 핵심 암호화 및 암호 해독 루틴의 사용자 지정 구현을 제공할 수 있습니다. 자세한 내용은 IAuthenticatedEncryptor의 를 참조하세요.
Docker 컨테이너 내에서 키를 지속적으로 유지하기
Docker 컨테이너를 호스트할 때는 키를 다음 중 하나에 저장해야 합니다.
- 컨테이너의 수명을 초과하여 유지되는 Docker의 볼륨인 폴더(예: 공유 볼륨 또는 호스트 마운트된 볼륨)
- 외부 공급자(예: Azure Blob Storage(
ProtectKeysWithAzureKeyVault섹션 참조) 또는 Redis)
Redis를 사용하여 키 영속화
Redis 데이터 지속성을 지원하는 Redis 버전만 키를 저장하는 데 사용해야 합니다. Azure Blob 스토리지는 지속성을 지원하므로 키를 저장하는 데 사용할 수 있습니다. 자세한 내용은 해당 GitHub 이슈를 참조하세요.
Logging
Information 또는 더 낮은 로깅 수준을 활성화하여 문제를 진단합니다. 다음 appsettings.json 파일은 데이터 보호 API의 정보 로깅을 사용하도록 설정합니다.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.DataProtection": "Information"
}
},
"AllowedHosts": "*"
}
로깅에 대한 자세한 내용은 .NET 및 ASP.NET Core의 로깅을 참조하세요.
추가 리소스
데이터 보호 시스템은 초기화되면 운영 환경에 따라 기본 설정을 적용합니다. 이러한 설정은 단일 컴퓨터에서 실행되는 앱에 적합합니다. 그러나 개발자가 기본 설정을 변경해야 하는 경우가 있습니다.
- 앱이 여러 머신에 분산되어 있습니다.
- 준수 이유로.
데이터 보호 시스템은 이러한 시나리오를 위한 여러 구성 API를 제공합니다.
Warning
데이터 보호 키 링은 구성 파일과 마찬가지로 적절한 권한을 사용하여 보호해야 합니다. 사용하지 않는 키를 암호화하도록 선택할 수 있지만, 이는 사이버 공격자가 새 키를 만드는 것을 방지하지는 않습니다. 따라서 앱의 보안이 영향을 받게 됩니다. 데이터 보호로 구성된 스토리지 위치는 구성 파일을 보호하는 방식과 비슷하게 앱 자체에 대한 액세스 권한이 제한되어야 합니다. 예를 들어, 키 링을 디스크에 저장하는 경우에는 파일 시스템 권한을 사용하세요. 웹앱이 실행되는 ID만 해당 디렉터리에 대한 읽기, 쓰기 및 만들기 액세스 권한이 있는지 확인합니다. Azure Blob Storage를 사용하는 경우 웹앱만 Blob 저장소에서 새 항목을 읽거나 쓰거나 만들 수 있어야 합니다.
확장 메서드 AddDataProtection는 데이터 보호 옵션을 구성하기 위해 함께 연결할 수 있는 여러 확장 메서드를 노출하는 IDataProtectionBuilder을 반환합니다.
이 문서에서 사용하는 데이터 보호 확장에는 다음과 같은 NuGet 패키지가 필요합니다.
Note
.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 작업 흐름(NuGet 문서)의 패키지 설치 및 관리 섹션에서 확인할 수 있습니다. 올바른 패키지 버전을 NuGet.org에서 확인하세요.
Azure Key Vault를 사용하여 키 보호(ProtectKeysWithAzureKeyVault)
개발자 자격 증명을 사용하여 Azure Key Vault 와 로컬로 상호 작용하려면 Visual Studio에서 스토리지 계정에 로그인하거나 Azure CLI로 로그인합니다. Azure CLI를 아직 설치하지 않은 경우 Azure CLI를 설치하는 방법을 참조하세요. Visual Studio를 사용하지 않는 경우 Visual Studio의 개발자 PowerShell 패널 또는 명령 셸에서 다음 명령을 실행할 수 있습니다.
az login
자세한 내용은 개발자 도구를 사용하여 Azure에 로그인을 참조하세요.
Entra 또는 Azure 포털에서 키 저장소를 설정할 때 경우:
Azure 역할 기반 액세스 제어(RABC)를 사용하도록 키 자격 증명 모음을 구성합니다. 로컬 개발 및 테스트를 포함하여 Azure Virtual Network에서 작동하지 않는 경우 네트워킹 단계에서 공용 액세스가 사용하도록 설정되어 있는지 확인합니다(선택됨). 공용 액세스를 사용하도록 설정하면 키 자격 증명 모음 엔드포인트만 노출됩니다. 인증된 계정은 여전히 액세스에 필요합니다.
Azure Managed Identity를 만들거나 사용하는 기존 Managed Identity에 Key Vault Crypto 사용자 역할을 추가합니다. 배포를 호스팅하는 Azure App Service에 Managed Identity 를 할당합니다.사용자가 할당한>Identity>>추가입니다.
Note
Azure CLI 또는 Visual Studio의 Azure 서비스 인증을 사용하여 Blob 액세스를 위해 권한 있는 사용자와 함께 로컬로 앱을 실행하려는 경우 Key Vault Crypto 사용자 역할을 사용하여 IAM(Access Control)에 개발자 Azure 사용자 계정을 추가합니다. Visual Studio를 통해 Azure CLI를 사용하려면 개발자 PowerShell 패널에서 명령을 실행하고
az login프롬프트에 따라 테넌트에 인증합니다.키 암호화가 활성화된 경우 키 파일의 키에는 "This key is encrypted with Azure Key Vault." 주석이 포함됩니다. 앱을 시작한 후 키 행 끝에 있는 상황에 맞는 메뉴에서 보기/편집 명령을 선택하여 키에 키 자격 증명 모음 보안이 적용되어 있는지 확인합니다.
필요에 따라 만료/회전된 키 자격 증명 모음 키를 기반으로 데이터 보호 키를 사용하여 페이로드의 암호를 해독하는 것에 대한 우려 없이 자동 키 자격 증명 모음 키 회전을 사용하도록 설정할 수 있습니다. 생성된 각 데이터 보호 키에는 암호화하는 데 사용되는 키 자격 증명 모음 키에 대한 참조가 포함됩니다. 만료된 키 볼트 키를 보관하고, 키 볼트에서 삭제하지 마세요. 또한 앱의 키 자격 증명 모음 구성에서 버전 없는 키 식별자를 사용합니다. 여기서는 식별자 끝에 키 GUID가 배치되지 않습니다(예:
https://contoso.vault.azure.net/keys/data-protection). 데이터 보호 키 회전 시 새 키 자격 증명 모음 키가 사용되도록 키 자격 증명 모음 키가 데이터 보호 키보다 더 자주 회전하는 두 키에 대해 비슷한 회전 기간을 사용합니다.
Azure Key Vault로 키를 보호하면 키 링 스토리지 위치를 비롯한 자동 데이터 보호 설정이 비활성화됩니다. Blob Storage에 키를 저장하도록 Azure Blob Storage 공급자를 구성하려면 ASP.NET Core의 키 스토리지 공급자에 대한 지침을 따르고 앱의 오버로드 중 PersistKeysToAzureBlobStorage 하나를 호출합니다. 다음 예제에서는 RBAC(역할 기반 액세스 제어)를 위해 Azure Managed TokenCredential 를 사용하여 Blob URI 및 토큰 자격 증명(Identity)을 허용하는 오버로드를 사용합니다.
Azure Key Vault 공급자를 구성하려면 오버로드 중 ProtectKeysWithAzureKeyVault 하나를 호출합니다. 다음 예제에서는 키 식별자 및 토큰 자격 증명(TokenCredential)을 허용하는 오버로드를 사용하고, 프로덕션 중 RBAC는 Managed Identity에 의존하며, 개발 및 테스트에서는 ManagedIdentityCredential에 의존합니다. 다른 오버로드는 키 볼트 클라이언트 또는 클라이언트 비밀이 있는 앱 클라이언트 ID를 허용합니다. 자세한 내용은 ASP.NET Core의 키 스토리지 공급자를 참조하세요.
Azure SDK의 API 및 인증에 대한 자세한 내용은 Azure 라이브러리를 사용하여 Azure 서비스에 .NET 앱 인증 및 Azure Identity역할 기반 액세스 제어를 사용하여 Key Vault 키, 인증서 및 비밀에 대한 액세스 제공을 참조하세요. 로깅 지침은 Azure SDK for .NET: 클라이언트 등록 없이 로깅하기을 참조하세요. 종속성 주입을 사용하는 앱의 경우, 앱은 로그 인프라를 생성하고 연결하기 위해 AddAzureClientsCore를 true로 전달하여 enableLogForwarding를 호출할 수 있습니다.
Azure Portal에서 키를 만들려면 빠른 시작: Azure Portal을 사용하여 Azure Key Vault에서 키 설정 및 검색을 참조하세요. 키에 최소한 Get, Unwrap Key및 Wrap Key 사용 권한을 부여합니다. 앱의 구성에 사용할 키 식별자를 기록합니다. 키 자격 증명 모음 키의 자동 회전을 사용하도록 설정하려는 경우 식별자 끝에 키 GUID가 배치되지 않는 버전 없는 키 식별자를 기록합니다(예: https://contoso.vault.azure.net/keys/data-protection).
Program 서비스가 등록된 파일에서:
TokenCredential? credential;
if (builder.Environment.IsProduction())
{
credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
// Local development and testing only
DefaultAzureCredentialOptions options = new()
{
// Specify the tenant ID to use the dev credentials when running the app locally
// in Visual Studio.
VisualStudioTenantId = "{TENANT ID}",
SharedTokenCacheTenantId = "{TENANT ID}"
};
credential = new DefaultAzureCredential(options);
}
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}: Azure 관리형 Identity 클라이언트 ID(GUID).
{TENANT ID}: 테넌트 ID입니다.
{APPLICATION NAME}: SetApplicationName 데이터 보호 시스템 내에서 이 앱의 고유한 이름을 설정합니다. 값은 앱 배포에서 일치해야 합니다.
{BLOB URI}: 키 파일에 대한 전체 URI입니다. URI는 키 파일을 만들 때 Azure Storage에서 생성됩니다. SAS를 사용하지 마세요.
{KEY IDENTIFIER}: 키 암호화에 사용되는 Azure Key Vault 키 식별자입니다. 액세스 정책을 사용하면 애플리케이션이 Get, Unwrap Key, 및 Wrap Key 사용 권한으로 키 자격 증명 보관소에 액세스할 수 있습니다. 키의 버전은 생성된 후 Entra 또는 Azure Portal의 키에서 가져옵니다. 키 자격 증명 모음 키의 자동 회전을 사용하도록 설정하는 경우 앱의 키 자격 증명 모음 구성에서 버전 없는 키 식별자를 사용해야 합니다. 여기서 키 GUID는 식별자 끝에 배치되지 않습니다(예: https://contoso.vault.azure.net/keys/data-protection).
앱이 Azure Key Vault와 통신하고 권한을 부여하려면 앱에서 Azure.Identity NuGet 패키지를 참조해야 합니다.
Note
.NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 작업 흐름(NuGet 문서)의 패키지 설치 및 관리 섹션에서 확인할 수 있습니다. 올바른 패키지 버전을 NuGet.org에서 확인하세요.
Note
비-Production환경에서는 인증을 간소화하기 위해 Azure 호스팅 환경에서 사용되는 자격 증명과 로컬 개발에 사용되는 자격 증명을 결합하여 Azure에 배포하는 앱을 개발하는 동안 이전 예제에서는 DefaultAzureCredential을 사용합니다. 자세한 내용은 시스템 할당 관리 ID를 사용하여 Azure 리소스에 Azure 호스팅 .NET 앱 인증을 참조하세요.
앱에서 이전 Azure 패키지(Microsoft.AspNetCore.DataProtection.AzureStorage 및 Microsoft.AspNetCore.DataProtection.AzureKeyVault)를 사용하는 경우, 이러한 참조를 제거하고Azure.Extensions.AspNetCore.DataProtection.Blobs 및 Azure.Extensions.AspNetCore.DataProtection.Keys 패키지로 업그레이드하는 것을 권장합니다. 최신 패키지는 주요 보안 및 안정성 문제를 해결합니다.
대체 SAS(공유 액세스 서명) 접근 방식: Azure Blob Storage의 키 Blob에 액세스하기 위해 Managed Identity 를 사용하는 대신 SAS 토큰으로 Blob URI를 허용하는 오버로드를 호출 PersistKeysToAzureBlobStorage 할 수 있습니다. 다음 예제에서는 앞의 예제와 같이 ManagedIdentityCredential (프로덕션) 또는 DefaultAzureCredential (개발 및 테스트) TokenCredential를 계속 사용합니다.
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{APPLICATION NAME}: SetApplicationName 데이터 보호 시스템 내에서 이 앱의 고유한 이름을 설정합니다. 값은 앱 배포에서 일치해야 합니다.
{BLOB URI WITH SAS}: 키 파일을 SAS 토큰과 함께 쿼리 문자열 매개 변수로 저장해야 하는 전체 URI입니다. 업로드된 키 파일에 대한 SAS를 요청할 때 Azure Storage에서 URI를 생성합니다.
{KEY IDENTIFIER}: 키 암호화에 사용되는 Azure Key Vault 키 식별자입니다. 액세스 정책을 사용하면 애플리케이션이 Get, Unwrap Key, 및 Wrap Key 사용 권한으로 키 자격 증명 보관소에 액세스할 수 있습니다. 키의 버전은 생성된 후 Entra 또는 Azure Portal의 키에서 가져옵니다. 키 자격 증명 모음 키의 자동 회전을 사용하도록 설정하는 경우 앱의 키 자격 증명 모음 구성에서 버전 없는 키 식별자를 사용해야 합니다. 여기서 키 GUID는 식별자 끝에 배치되지 않습니다(예: https://contoso.vault.azure.net/keys/data-protection).
파일 시스템에 키 유지(PersistKeysToFileSystem)
%LOCALAPPDATA% 기본 위치 대신 UNC 공유 경로에 키를 저장하려면, PersistKeysToFileSystem을 사용하여 시스템을 구성하십시오.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
}
Warning
키 지속성 위치를 변경하면 DPAPI가 적절한 암호화 메커니즘인지 여부를 알 수 없으므로 시스템에서 더 이상 미사용 키를 자동으로 암호화하지 않습니다.
데이터베이스에 키 유지(PersistKeysToDbContext)
EntityFramework를 사용하는 데이터베이스에 키를 저장하려면 Microsoft.AspNetCore.DataProtection.EntityFrameworkCore 패키지를 사용하여 시스템을 구성합니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToDbContext<DbContext>()
}
위 코드는 구성된 데이터베이스에 키를 저장합니다. 사용되는 데이터베이스 컨텍스트는 IDataProtectionKeyContext를 구현해야 합니다.
IDataProtectionKeyContext는 DataProtectionKeys 속성을 노출합니다.
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
이 속성은 키가 저장되는 테이블을 나타냅니다. 테이블을 수동으로 또는 DbContext 마이그레이션을 사용하여 만듭니다. 자세한 내용은 DataProtectionKey를 참조하세요.
키 보호 구성 API(ProtectKeysWith\*)
시스템을 미사용 상태의 키를 보호하도록 구성하려면 ProtectKeysWith\* 구성 API 중 하나를 호출할 수 있습니다. UNC 공유에 키를 저장하고 특정 X.509 인증서를 사용하여 미사용 키를 암호화하는 아래 예제를 살펴보세요.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(Configuration["Thumbprint"]);
}
파일에서 로드된 인증서와 같이 X509Certificate2에 ProtectKeysWithCertificate를 제공할 수 있습니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", Configuration["Thumbprint"]));
}
기본 제공 키 암호화 메커니즘에 대한 자세한 예제 및 논의는 ASP.NET Core를 사용하여 Windows 및 Azure의 미사용 키 암호화를 참조하세요.
인증서를 사용하여 키 보호 해제(UnprotectKeysWithAnyCertificate)
X509Certificate2인 UnprotectKeysWithAnyCertificate 인증서 배열을 사용하여 인증서를 교체하고 정지 상태의 키를 복호화할 수 있습니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate(
new X509Certificate2("certificate.pfx", Configuration["MyPasswordKey"));
.UnprotectKeysWithAnyCertificate(
new X509Certificate2("certificate_old_1.pfx", Configuration["MyPasswordKey_1"]),
new X509Certificate2("certificate_old_2.pfx", Configuration["MyPasswordKey_2"]));
}
기본 키 수명 설정(SetDefaultKeyLifetime)
기본 90일 대신 14일의 키 수명을 사용하도록 시스템을 구성하려면 다음을 사용합니다 SetDefaultKeyLifetime.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
}
애플리케이션 이름 설정(SetApplicationName)
기본적으로 데이터 보호 시스템은 앱들 간에 동일한 물리적 키 리포지토리를 공유하는 경우에도 콘텐츠 루트 경로를 기반으로 앱을 서로 격리합니다. 이러한 격리에 따라 앱이 다른 앱의 보호된 페이로드를 알 수 없게 됩니다.
앱 간에 보호된 페이로드를 공유하려면:
- 각 앱에서 SetApplicationName을 같은 값으로 구성합니다.
- 각 앱에서 동일한 버전의 데이터 보호 API 스택을 사용합니다. 앱의 프로젝트 파일에서 다음 중 하나를 수행합니다.
- Microsoft.AspNetCore.App metapackage를 통해 동일한 공유 프레임워크 버전을 참조합니다.
- 동일한 데이터 보호 패키지 버전을 참조합니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}");
}
SetApplicationName이 DataProtectionOptions.ApplicationDiscriminator를 내부적으로 설정합니다. 판별자가 사용되는 방법에 대한 자세한 내용은 이 문서의 뒷부분에 나오는 다음 섹션을 참조하세요.
자동 키 생성 사용 안 함(DisableAutomaticKeyGeneration)
키의 만료가 가까워지면 앱이 자동으로 키를 롤링(새 키 만들기)하지 못하도록 해야 하는 시나리오가 있을 수 있습니다. 이 시나리오의 한 가지 예로 기본/보조 관계로 설정된 앱을 들 수 있습니다. 여기서 기본 앱은 키 관리 문제를 담당하고, 보조 앱은 키 링에 대한 읽기 전용 보기만 가능합니다. 보조 앱은 DisableAutomaticKeyGeneration을 사용하여 시스템을 구성함으로써 키 링을 읽기 전용으로 취급하도록 구성할 수 있습니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.DisableAutomaticKeyGeneration();
}
애플리케이션별 격리
데이터 보호 시스템이 ASP.NET Core 호스트에 의해 제공되는 경우, 앱이 동일한 작업자 프로세스 계정에서 실행되고 동일한 마스터 키 링 자료를 사용하는 경우에도 자동으로 앱을 서로 격리합니다. 이는 System.Web의 <machineKey> 요소의 IsolateApps 한정자와 비슷합니다.
격리 메커니즘은 로컬 컴퓨터에 있는 각 앱을 고유한 테넌트로 간주하는 방식으로 작동합니다. 따라서 지정된 앱에 대해 루트된 IDataProtector에는 자동으로 앱 ID가 판별자(ApplicationDiscriminator)로 포함됩니다. 앱의 고유 ID는 앱의 실제 경로입니다.
- IIS에 호스트되는 앱의 경우, 고유 ID는 앱의 IIS 실제 경로입니다. 앱이 웹 팜 환경에 배포된 경우, 웹 팜에 있는 모든 머신에서 IIS 환경이 비슷하게 구성되었다는 가정하에 이 값은 일정합니다.
- Kestrel 서버에서 실행되는 자체 호스트 앱의 경우, 고유 ID는 디스크에 있는 앱의 실제 경로입니다.
고유 식별자는 재설정-개별 앱과 컴퓨터 자체의 재설정-이 이루어져도 지속되도록 설계되었습니다.
이 격리 메커니즘에서는 앱이 악성이 아니라고 가정합니다. 악성 앱은 동일한 작업자 프로세스 계정에서 실행되는 다른 앱에 언제든지 영향을 줄 수 있습니다. 앱이 상호 신뢰하지 않는 공유 호스트 환경에서는 호스트 공급자가 앱의 기본 키 리포지토리를 분리하는 등 앱 간에 OS 수준 격리를 유지하기 위한 조치를 취해야 합니다.
데이터 보호 시스템이 ASP.NET Core 호스트에 의해 제공되지 않은 경우(예를 들어, DataProtectionProvider 구체적인 형식을 통해 인스턴스화한 경우), 앱 격리가 기본적으로 사용하지 않도록 설정됩니다. 앱 격리가 사용하지 않도록 설정되면, 동일한 키 링 자료를 사용하는 모든 앱은 적절한 용도를 제공하는 한 페이로드를 공유할 수 있습니다. 이 환경에서 앱 격리를 제공하려면 구성 개체에 대해 SetApplicationName 메서드를 호출하고 각 앱의 고유한 이름을 제공하세요.
데이터 보호와 앱 격리
앱 격리 시 다음을 고려해야 합니다.
여러 앱이 동일한 키 리포지토리를 가리킨다면 그 의도는 앱이 동일한 마스터 키 자료를 공유하도록 하는 것입니다. 데이터 보호는 키 링을 공유하는 모든 앱이 해당 키 링에 있는 모든 항목에 액세스할 수 있다는 가정하에 개발됩니다. 애플리케이션 고유 식별자는 키 링이 제공하는 키에서 파생된 애플리케이션별 키를 격리하는 데 사용됩니다. 추가 격리를 적용하기 위해 Azure KeyVault가 제공하는 것과 같은 항목 수준 권한은 필요하지 않습니다. 항목 수준 권한을 시도하면 애플리케이션 오류가 발생합니다. 기본 제공 애플리케이션 격리를 사용하지 않으려면 개별적인 키 저장소 위치를 사용해야 하며 애플리케이션 간에 공유되지 않아야 합니다.
애플리케이션 판별자(ApplicationDiscriminator)는 여러 앱이 동일한 마스터 키 재질을 공유하도록 하되 암호화 페이로드는 서로 구분하는 용도로 사용됩니다. 앱이 다른 앱의 암호화 페이로드를 읽을 수 있으려면 동일한 애플리케이션 판별자를 가져야 합니다. 동일한 애플리케이션 판별자는
SetApplicationName을 호출하여 설정할 수 있습니다.앱이 손상된 경우(예: RCE 공격에 의해) 해당 앱에 액세스할 수 있는 모든 마스터 키 자료도 보호 상태와 관계없이 손상된 것으로 간주되어야 합니다. 이는 두 앱이 동일한 리포지토리를 가리키는 경우, 서로 다른 앱 판별자를 사용하는 경우에도 하나의 앱의 손상되면 두 앱이 모두 손상된 것과 기능적으로 동일함을 의미합니다.
이 "두 모두에 대한 타협과 기능적으로 동일한" 조항은 두 앱이 비활성 상태에서 키를 보호하기 위해 각각 다른 메커니즘을 사용하는 경우에도 적용됩니다. 이는 일반적으로 사용되는 구성이 아닙니다. 미사용 보호 메커니즘은 사이버 공격이 리포지토리에 대한 읽기 액세스 권한을 얻는 경우 보호를 제공하기 위한 것입니다. 리포지토리에 대한 쓰기 액세스 권한을 얻는 사이버 공격(앱 내에서 코드 실행 권한을 획득했기 때문일 수 있습니다)은 스토리지에 악성 키를 삽입할 수 있습니다. 데이터 보호 시스템은 의도적으로 키 리포지토리에 대한 쓰기 액세스 권한을 얻는 사이버 공격자에 대한 보호를 제공하지 않습니다.
앱이 다른 앱과 진정으로 격리된 상태로 유지되려면 서로 다른 키 리포지토리를 사용해야 합니다. 이는 자연스럽게 “격리된”에 대한 정의를 벗어나게 됩니다. 다른 앱의 데이터 저장소에 대한 읽기 및 쓰기 권한을 갖는 앱은 격리되지 않습니다.
UseCryptographicAlgorithms을 사용하여 알고리즘을 변경하기
데이터 보호 스택을 통해 새로 생성된 키에서 사용하는 기본 알고리즘을 변경할 수 있습니다. 이 작업을 수행하는 가장 간단한 방법은 구성 콜백에서 호출 UseCryptographicAlgorithms 하는 것입니다.
services.AddDataProtection()
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
기본 EncryptionAlgorithm은 AES-256-CBC이고, 기본 ValidationAlgorithm은 HMACSHA256입니다. 기본 정책은 시스템 관리자가 설정하거나 머신 전체에 적용되는 정책을 통해 설정할 수 있으며, UseCryptographicAlgorithms를 명시적으로 호출하면 기본 정책이 재정의됩니다.
UseCryptographicAlgorithms를 호출하면 미리 정의된 기본 제공 목록에서 원하는 알고리즘을 지정할 수 있습니다. 알고리즘의 구현에 대해서는 신경 쓸 필요가 없습니다. 위 시나리오에서 데이터 보호 시스템은 Windows에서 실행되는 경우 AES의 CNG 구현을 사용하려고 시도합니다. 그렇지 않으면 관리 System.Security.Cryptography.Aes 되는 클래스로 돌아갑니다.
호출 UseCustomCryptographicAlgorithms을 통해 구현을 수동으로 지정할 수 있습니다.
Tip
알고리즘을 변경해도 키 링에 있는 기존 키는 영향을 받지 않습니다. 새로 생성되는 키만 영향을 받습니다.
사용자 지정 관리형 알고리즘 지정
사용자 지정 관리 알고리즘을 지정하려면 구현 형식을 ManagedAuthenticatedEncryptorConfiguration 가리키는 인스턴스를 만듭니다.
serviceCollection.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new ManagedAuthenticatedEncryptorConfiguration()
{
// A type that subclasses SymmetricAlgorithm
EncryptionAlgorithmType = typeof(Aes),
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// A type that subclasses KeyedHashAlgorithm
ValidationAlgorithmType = typeof(HMACSHA256)
});
일반적으로 *Type 속성은 매개 변수 없는 퍼블릭 ctor를 통해 구체적이고 인스턴스화 가능한 SymmetricAlgorithm 및 KeyedHashAlgorithm의 구현을 가리켜야 합니다. 단, 시스템에서 편의를 위해 특수 사례로 취급하는 typeof(Aes)와 같은 값도 있습니다.
Note
SymmetricAlgorithm은 키 길이가 128비트 이상이고 블록 크기가 64비트 이상이어야 하며, PKCS #7 패딩을 사용하여 CBC 모드 암호화를 지원해야 합니다. KeyedHashAlgorithm은 다이제스트 크기가 >=128비트(128비트 이상)이어야 하며, 해시 알고리즘의 다이제스트 길이와 동일한 길이의 키를 지원해야 합니다. KeyedHashAlgorithm은 반드시 HMAC여야 할 필요는 없습니다.
사용자 지정 Windows CNG 알고리즘 지정
HMAC 유효성 검사와 함께 CBC 모드 암호화를 사용하여 사용자 지정 Windows CNG 알고리즘을 CngCbcAuthenticatedEncryptorConfiguration 지정하려면 알고리즘 정보를 포함하는 인스턴스를 만듭니다.
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngCbcAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256,
// Passed to BCryptOpenAlgorithmProvider
HashAlgorithm = "SHA256",
HashAlgorithmProvider = null
});
Note
대칭 블록 암호 알고리즘은 키 길이가 >= 128비트(128비트 이상)이고 블록 크기가 >= 64비트(64비트 이상)이어야 하며, PKCS #7 패딩을 사용하여 CBC 모드 암호화를 지원해야 합니다. 해시 알고리즘은 다이제스트 크기가 >= 128비트 이상이어야 하며, BCRYPT_ALG_HANDLE_HMAC_FLAG 플래그를 사용하여 열 수 있어야 합니다. *Provider 속성을 null로 설정하면 지정된 알고리즘에 대해 기본 공급자를 사용할 수 있습니다. 자세한 내용은 BCryptOpenAlgorithmProvider 설명서를 참조하세요.
Galois/카운터 모드 암호화와 유효성 검사를 사용하여 사용자 지정 Windows CNG 알고리즘을 지정하려면, 알고리즘 정보가 포함된 CngGcmAuthenticatedEncryptorConfiguration 인스턴스를 만드십시오.
services.AddDataProtection()
.UseCustomCryptographicAlgorithms(
new CngGcmAuthenticatedEncryptorConfiguration()
{
// Passed to BCryptOpenAlgorithmProvider
EncryptionAlgorithm = "AES",
EncryptionAlgorithmProvider = null,
// Specified in bits
EncryptionAlgorithmKeySize = 256
});
Note
대칭 블록 암호 알고리즘은 키 길이가 >= 128비트(128비트 이상)이고 블록 크기가 정확히 128비트이어야 하며 GCM 암호화를 지원해야 합니다. 지정된 알고리즘에 EncryptionAlgorithmProvider 기본 공급자를 사용하도록 속성을 null로 설정할 수 있습니다. 자세한 내용은 BCryptOpenAlgorithmProvider 설명서를 참조하세요.
그 밖의 사용자 지정 알고리즘 지정
데이터 보호 시스템은 1급 API로 노출되지 않지만, 거의 모든 종류의 알고리즘을 지정할 수 있을 만큼 확장성이 뛰어납니다. 예를 들어, 하나의 HSM(하드웨어 보안 모듈) 내에 포함된 모든 키를 유지하고 핵심 암호화 및 암호 해독 루틴의 사용자 지정 구현을 제공할 수 있습니다. 자세한 내용은 IAuthenticatedEncryptor의 를 참조하세요.
Docker 컨테이너 내에서 키를 지속적으로 유지하기
Docker 컨테이너를 호스트할 때는 키를 다음 중 하나에 저장해야 합니다.
- 컨테이너의 수명을 초과하여 유지되는 Docker의 볼륨인 폴더(예: 공유 볼륨 또는 호스트 마운트된 볼륨)
-
Azure Blob Storage(AzureKey Vault를
ProtectKeysWithAzureKeyVault사용하여 키 보호 섹션에 표시됨) 또는 Redis와 같은 외부 공급자입니다.
Redis를 사용하여 키 영속화
Redis 데이터 지속성을 지원하는 Redis 버전만 키를 저장하는 데 사용해야 합니다. Azure Blob 스토리지는 지속성을 지원하므로 키를 저장하는 데 사용할 수 있습니다. 자세한 내용은 해당 GitHub 이슈를 참조하세요.
Logging
Information 또는 더 낮은 로깅 수준을 활성화하여 문제를 진단합니다. 다음 appsettings.json 파일은 데이터 보호 API의 정보 로깅을 사용하도록 설정합니다.
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.DataProtection": "Information"
}
}
}
로깅에 대한 자세한 내용은 .NET 및 ASP.NET Core의 로깅을 참조하세요.
추가 리소스
ASP.NET Core