ASP.NET Core 5.0 에서 IDataProtector 활용하여 데이터 보호하는 방법
ASP.NET Core 5.0 에서 IDataProtector 활용하여 데이터 보호하는 방법
데이터를 암호화하고 해독하는 데 사용할 수 있는 ASP.NET Core 기본 제공 데이터 보호 메커니즘인 IDataProtector 에 대해 알아볼 것입니다.
IDataProtector로 데이터 암호화 및 암호 해독
IDataProtector는 데이터 보호 서비스를 제공하는 인터페이스입니다. 해당 기능을 사용하려면 해당 데이터 보호 서비스를 지정된 IServiceCollection 에 추가한 다음 종속성 주입(DI) 을 사용하여 INJECT 해야 합니다.
예를 들어 고유 키값이 guid 문자열 형태로 구분되어 있는 경우 상세화면에서 해당 URL 을 통해 쉽게 키 코드값을 보실 수 있습니다.

보호 차원 상 guid 값 파라미터를 데이터 보호 하기 위해서 아래와 같이 startup.cs 에서 서비스를 수정해 보겠습니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<EmployeeContext>(opts =>
opts.UseSqlServer(Configuration.GetConnectionString("sqlConnection")));
services.AddScoped<IEmployeeRepository, EmployeeRepository>();
//보호 설정
services.AddDataProtection();
services.AddControllersWithViews();
}
IDataProtector 및 DI 를 사용하여 데이터 보호 개체 만들기
이를 사용하기 위한 컨트롤러를 열어서 DI 를 통해 데이터 보호 객체를 만듭니다. IDataProtector 유형의 개체를 생성하는 것을 볼 수 있습니다.
private readonly IDataProtector _protector;
public EmployeesController(IEmployeeRepository repo, IDataProtectionProvider provider)
{
_repo = repo;
_protector = provider.CreateProtector("EmployeesApp.EmployeesController");
}
IDataProtector 개체를 생성하였고, 이를 성공적으로 수행하기 위해서는 CreateProtector 메소드가 포함된 IDataProtectionProvider 개체를 필요로 합니다. 이 두개의 인터페이스 모두 Microsoft.AspNetCore.DataProtection 의 namespace 의 일부이므로 using 문을 통해 사용합니다.
이제 guid 인 id 값을 보호하기 위해서 별도로 EncryptedId 속성을 하나 만듭니다.
public class Employee
{
public Guid Id { get; set; }
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; }
[Required(ErrorMessage = "Age is required")]
public int Age { get; set; }
[Required(ErrorMessage = "Account number is required")]
public string AccountNumber { get; set; }
[NotMapped]
public string EncryptedId { get; set; }
}
guid 의 id 값을 foreach 구문을 통해 반복하여 id 값을 Protect() 함수를 통해 암호화 하여 새롭게 만든 속성인 EncryptedId 에 암호 값을 할당합니다.
public IActionResult Index()
{
var employees = _repo.GetAll();
foreach (var emp in employees)
{
var stringId = emp.Id.ToString();
emp.EncryptedId = _protector.Protect(stringId);
}
return View(employees);
}
view 의 list 목록에서 상세보기 링크에 키값이 아닌 암호값을 파라미터로 전송하도록 지정합니다.
<a asp-action="Details" asp-route-id="@item.EncryptedId">Details</a> |
상세 화면 Detail 에서 암호화 값인 id 값을 받아 복호화 합니다. 복호화 함수는 Unprotect() 통해 변환 가능합니다.
public IActionResult Details(string id)
{
var guid_id = Guid.Parse(_protector.Unprotect(id));
var employee = _repo.GetEmployee(guid_id);
return View(employee);
}
상세보기를 누르면 상세화면 이동 url 에 암호화된 id 파라미터 값이 보입니다.

purpose string 알아보기
_protector = provider.CreateProtector("EmployeesApp.EmployeesController");
설명한 대로 보호자 개체(protector object) 를 생성하려면 유형 IDataProtectionProvider 와 메서드의 개체가 필요합니다. 그러나 메서드 CreateProtector 메소드에서 추가 매개변수 값을 볼 수 있습니다. 해당 값을 "Purpose String" 이라고 합니다.
모든 protector 에는 고유한 "purpose string" 이 있어야 하며, 암호화(cryptographic) 소비자(consumers) 간에 격리(isolation)를 제공합니다. 즉, 두 개의 IDataProtector 인스턴스(다른 "purpose string" 로 생성됨)는 서로의 페이로드(payloads) 를 읽을 수 없고 자신의 페이로드(payloads) 만 읽을 수 있습니다.
protector object 가 다른 protector 의 페이로드(payload) 를 읽으려고 하면 예외가 throw됩니다. 컨트롤러를 약간 수정해 보겠습니다.
private readonly IEmployeeRepository _repo;
private readonly IDataProtector _protector;
private readonly IDataProtector _protectorTest;
public EmployeesController(IEmployeeRepository repo, IDataProtectionProvider provider)
{
_repo = repo;
_protector = provider.CreateProtector("EmployeesApp.EmployeesController");
_protectorTest = provider.CreateProtector("TestProtector");
}
public IActionResult Index()
{
var employees = _repo.GetAll();
foreach (var emp in employees)
{
var stringId = emp.Id.ToString();
emp.EncryptedId = _protector.Protect(stringId);
}
var testData = _protectorTest.Protect("Test");
var unprotectedTest = _protector.Unprotect(testData);
return View(employees);
}
서로 다른 IDataProtector 인스턴스를 만들었습니다.
_protector = provider.CreateProtector("EmployeesApp.EmployeesController");
_protectorTest = provider.CreateProtector("TestProtector");
그리고 이를 암복호화를 하게 되면,
var testData = _protectorTest.Protect("Test");
var unprotectedTest = _protector.Unprotect(testData);
아래와 같이 payload 값이 달라 오류 발생됩니다.

Data Protection 제한시간 설정하기
보호된 페이로드가 특정 기간 후에 만료되기를 원하는 상황이 있습니다. 이를 위해 ITimeLimitedDataProtector 인터페이스를 사용할 수 있습니다. 이 언급된 인터페이스의 인스턴스를 생성하려면 IDataProtector 의 인스턴스가 있어야 하고, 확장 메서드인 ToTimeLmitedDataProtector 으로 호출해야 합니다.
따라서 예제를 통해 시간 제한 페이로드를 생성하는 방법을 알아보겠습니다.
2분 정도 설정을 한 다음에, 3초 후에 이를 호출하게 되면 오류가 발생됩니다.
public IActionResult Index()
{
//Previous code removed for the example clarity
var timeLimitedProtector = _protector.ToTimeLimitedDataProtector();
var timeLimitedData = timeLimitedProtector.Protect("Test timed protector", lifetime: TimeSpan.FromSeconds(2));
//just to test that this action works as long as life-time hasn't expired
var timedUnprotectedData = timeLimitedProtector.Unprotect(timeLimitedData);
Thread.Sleep(3000);
var anotherTimedUnprotectTry = timeLimitedProtector.Unprotect(timeLimitedData);
return View(employees);
}
만료되어 오류 발생되었습니다.

ASP.NET Core 에서 Data Protection 환경 설정 지정하기
asp.net core 에서 startup 클래스에 이를 등록할 수 있습니다. 여기서 PersistKeysToFileSystem 메소드를 사용할 수 있는데요. 이를 실행하면 해당 폴더에 xml 형태의 파이링 존재합니다.
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"bin\debug\configuration"));
열어보면, 생성시간, 만료시간, validation 알고리즘과 master key 값 까지 보여집니다. 하지만 key 값이 암호화 되어 있지 않아 좋은 코드는 아닙니다. 이를 개선해 보죠.

단지, ProtectKeysWithDpapi() 함수를 추가했는데요. 기존의 xml 파일은 삭제하고 아래 코드로 변경하고 실행하면.....
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"bin\debug\configuration"))
.ProtectKeysWithDpapi();
데이터 값이 암호화 되어 있는 것을 확인 가능합니다.

ProtectKeysWithDpapi() 함수 뿐만 아니라, 추가적인 메소드들이 몇개 더 존재합니다.

이제, 만료시간을 지정하는 방법도 알아보죠. 기본 시간은 90 일 입니다. 너무 길다 생각 들면 수정도 가능합니다.
SetDefaultKeyLifetime() 함수를 통해 만료시간을 10 일로 단축 하였습니다.
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"bin\debug\configuration"))
.ProtectKeysWithDpapi()
.SetDefaultKeyLifetime(TimeSpan.FromDays(10));
다시 실행해 보면, 만료 시간이 생성된 시간 기준으로 90일이 아닌 10일로 지정되어 변경된것을 확인 가능합니다.

추가적인 환경 옵션에 대해서는 아래 msdn 을 참고하시길 바랍니다.
Data Protection configuration in ASP.NET Core
Discover topics that explain how to configure Data Protection in ASP.NET Core.
docs.microsoft.com
변역 및 참고 사이트
https://code-maze.com/data-protection-aspnet-core/
Protecting Data with IDataProtector in ASP.NET Core - Code Maze
In this article, we are going to learn how to use IDataProtector to protect the sensitive data in the ASP.NET Core application.
code-maze.com
https://www.ttmind.com/TechPost/aspnet-core-data-protection-using-idataprotectionprovider-wi
ASP.NET Core Data Protection using IDataProtectionProvider With Example
ASP.NET Core Data Protection using IDataProtectionProvider With ExampleFind this Demo on GithubThis Process is easier for developers to use solid Cryptog
www.ttmind.com