테이터 보호: 키가 취소된 페이로드의 보호 해제하기
- 본 번역문서의 원문은 Unprotecting payloads whose keys have been revoked docs.microsoft.com 입니다.
ASP.NET Core 데이터 보호 API는 무기한 기밀 페이로드의 유지를 목적으로 설계되지 않았습니다. 무기한 저장 시나리오에는 Windows CNG DPAPI나 Azure 권한 관리 같은 다른 기술이 더 적합하며, 이런 기술들은 그에 상응하는 강력한 키 관리 기능을 갖추고 있습니다. 그러나 개발자가 ASP.NET Core 데이터 보호 API를 이용해서 기밀 데이터를 장기간 보호하는 행위 자체를 금지하는 것은 아닙니다. 키는 키 링에서 절대로 제거되지 않으므로, 키가 사용 가능하고 유효하기만 하다면 언제나 IDataProtector.Unprotect 메서드로 원본 페이로드를 복구할 수 있습니다.
그러나 개발자가 취소된 키를 이용해서 보호된 데이터를 보호 해제하려고 시도할 경우 문제가 발생하는데, IDataProtector.Unprotect 메서드가 예외를 던지기 때문입니다. 단기 및 임시 페이로드는 (인증 토큰 같은) 시스템에서 손쉽게 재생성 할 수 있으므로 이런 유형의 페이로드는 크게 문제가 되지 않으며, 최악의 경우가 발생하더라도 사용자가 다시 로그인하면 그만입니다. 그러나 영속화된 페이로드의 경우에는 Unprotect 메서드가 예외를 던지는 상황이 발생하면 간과할 수 없는 데이터 유실이 발생하게 됩니다.
IPersistedDataProtector
키가 해제된 경우에도 페이로드를 보호 해제할 수 있도록 허용하는 시나리오를 지원하기 위해서 데이터 보호 시스템에는 IPersistedDataProtector 형식이 포함되어 있습니다. IPersistedDataProtector 인터페이스의 인스턴스를 얻기 위해서는 그냥 일반적인 IDataProtector의 인스턴스를 얻은 다음, 해당 인스턴스를 IPersistedDataProtector 형식으로 형변환하기만 하면 됩니다.
노트
모든 IDataProtector 인스턴스를 IPersistedDataProtector 형식으로 형변환 할 수 있는 것은 아닙니다. 따라서 개발자는 C#의 as 연산자나 비슷한 다른 기능을 이용해서 유효하지 않은 형변환 시도로부터 발생하는 런타임 예외를 방지하고, 형변환에 실패하는 경우에 대한 적절한 처리를 준비해야 합니다.
IPersistedDataProtector 인터페이스는 다음과 같은 API 표면을 노출합니다:
DangerousUnprotect(byte[] protectedData, bool ignoreRevocationErrors,
out bool requiresMigration, out bool wasRevoked) : byte[]
이 API는 보호된 페이로드를 전달 받아서 (byte 배열로) 보호 해제된 페이로드를 반환합니다. 이 API에는 문자열 기반의 오버로드가 존재하지 않습니다. 마지막 두 가지 out 매개변수는 다음과 같습니다.
-
requiresMigration: 페이로드를 보호하는데 사용된 키가 더 이상 활성화 된 기본 키가 아닌 경우 true로 설정됩니다 (페이로드를 보호하는데 사용된 키가 오래되어 키 롤링 작업이 발생한 경우 등). 업무 규칙에 따라서는 호출자가 페이로드를 다시 보호해야 하는 경우도 있습니다.
-
wasRevoked: 페이로드를 보호하는데 사용된 키가 취소된 경우 true로 설정됩니다.
주의
DangerousUnprotect 메서드를 호출할 때 ignoreRevocationErrors 매개변수를 true로 전달하는 경우에는 특히 주의하시기 바랍니다. 만약 이 메서드를 호출한 후 wasRevoked 값으로 true가 반환된다면, 페이로드 보호에 사용된 키가 취소되었으며 페이로드의 신뢰성이 의심스러운 것으로 간주되어야 합니다. 그런 경우, 신뢰할 수 없는 웹 클라이언트에서 전송된 페이로드 등을 제외한, 보안 데이터베이스에서 가져온 페이로드처럼 별도로 신뢰성을 확실하게 보장할 수 있는 경우에만 보호 해제된 페이로드를 이용해서 작업을 수행해야 합니다.
using System;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.Extensions.DependencyInjection;
public class Program
{
public static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection()
// point at a specific folder and use DPAPI to encrypt keys
.PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
.ProtectKeysWithDpapi();
var services = serviceCollection.BuildServiceProvider();
// get a protector and perform a protect operation
var protector = services.GetDataProtector("Sample.DangerousUnprotect");
Console.Write("Input: ");
byte[] input = Encoding.UTF8.GetBytes(Console.ReadLine());
var protectedData = protector.Protect(input);
Console.WriteLine($"Protected payload: {Convert.ToBase64String(protectedData)}");
// demonstrate that the payload round-trips properly
var roundTripped = protector.Unprotect(protectedData);
Console.WriteLine($"Round-tripped payload: {Encoding.UTF8.GetString(roundTripped)}");
// get a reference to the key manager and revoke all keys in the key ring
var keyManager = services.GetService<IKeyManager>();
Console.WriteLine("Revoking all keys in the key ring...");
keyManager.RevokeAllKeys(DateTimeOffset.Now, "Sample revocation.");
// try calling Protect - this should throw
Console.WriteLine("Calling Unprotect...");
try
{
var unprotectedPayload = protector.Unprotect(protectedData);
Console.WriteLine($"Unprotected payload: {Encoding.UTF8.GetString(unprotectedPayload)}");
}
catch (Exception ex)
{
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
// try calling DangerousUnprotect
Console.WriteLine("Calling DangerousUnprotect...");
try
{
IPersistedDataProtector persistedProtector = protector as IPersistedDataProtector;
if (persistedProtector == null)
{
throw new Exception("Can't call DangerousUnprotect.");
}
bool requiresMigration, wasRevoked;
var unprotectedPayload = persistedProtector.DangerousUnprotect(
protectedData: protectedData,
ignoreRevocationErrors: true,
requiresMigration: out requiresMigration,
wasRevoked: out wasRevoked);
Console.WriteLine($"Unprotected payload: {Encoding.UTF8.GetString(unprotectedPayload)}");
Console.WriteLine($"Requires migration = {requiresMigration}, was revoked = {wasRevoked}");
}
catch (Exception ex)
{
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
}
}
/*
* SAMPLE OUTPUT
*
* Input: Hello!
* Protected payload: CfDJ8LHIzUCX1ZVBn2BZ...
* Round-tripped payload: Hello!
* Revoking all keys in the key ring...
* Calling Unprotect...
* CryptographicException: The key {...} has been revoked.
* Calling DangerousUnprotect...
* Unprotected payload: Hello!
* Requires migration = True, was revoked = True
*/
- 권한부여: 개요 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