ASP.NET Core에서 보호 된 페이로드의 수명 제한Limit the lifetime of protected payloads in ASP.NET Core

일부 시나리오에서는 응용 프로그램 개발자가 일정 시간 후에 만료되는 보호된 페이로드를 생성해야 할 수도 있습니다.There are scenarios where the application developer wants to create a protected payload that expires after a set period of time. 예를 들어, 비밀번호 재설정 토큰으로 한 시간 동안만 유효한 보호된 페이로드 같은 경우를 들 수 있습니다.For instance, the protected payload might represent a password reset token that should only be valid for one hour. 물론 개발자가 내부적으로 만료 일자를 담고 있는 페이로드 형식을 직접 만드는 것도 불가능한 일은 아니고, 오히려 고급 개발자라면 이런 방식을 더 선호할 수도 있겠지만, 만료를 관리하는 이런 작업은 대다수 개발자에게는 번거러운 작업입니다.It's certainly possible for the developer to create their own payload format that contains an embedded expiration date, and advanced developers may wish to do this anyway, but for the majority of developers managing these expirations can grow tedious.

개발자가 이런 작업을 손쉽게 처리할 수 있도록 Microsoft.AspNetCore.DataProtection.Extensions 패키지에는 일정 시간 뒤에 자동으로 만료되는 페이로드를 생성하는 유틸리티 API들이 포함되어 있습니다To make this easier for our developer audience, the package Microsoft.AspNetCore.DataProtection.Extensions contains utility APIs for creating payloads that automatically expire after a set period of time. 이 API들은 ITimeLimitedDataProtector 형식으로 제공됩니다.These APIs hang off of the ITimeLimitedDataProtector type.

API 사용 방법API usage

ITimeLimitedDataProtector 인터페이스는 시간 제한/자체 만료 페이로드를 보호하거나 보호 해제하는 작업을 수행하기 위한 핵심 인터페이스입니다.The ITimeLimitedDataProtector interface is the core interface for protecting and unprotecting time-limited / self-expiring payloads. ITimeLimitedDataProtector의 인스턴스를 생성하려면, 먼저 특정 용도를 지정해서 생성한 일반적인 IDataProtector의 인스턴스가 필요합니다.To create an instance of an ITimeLimitedDataProtector, you'll first need an instance of a regular IDataProtector constructed with a specific purpose. IDataProtector의 인스턴스를 얻은 뒤에 IDataProtector.ToTimeLimitedDataProtector 확장 메서드를 호출해서 만료 기능이 내장된 보호자를 다시 얻습니다.Once the IDataProtector instance is available, call the IDataProtector.ToTimeLimitedDataProtector extension method to get back a protector with built-in expiration capabilities.

ITimeLimitedDataProtector 는 다음과 같은 API 표면 및 확장 메서드를 노출합니다.ITimeLimitedDataProtector exposes the following API surface and extension methods:

  • CreateProtector(string purpose) : ITimeLimitedDataProtector-이 API는 기존 비슷합니다 IDataProtectionProvider.CreateProtector 만들려면 사용할 수 있다는 점에서 체인 용도의 루트 시간이 제한 된 보호기를에서.CreateProtector(string purpose) : ITimeLimitedDataProtector - This API is similar to the existing IDataProtectionProvider.CreateProtector in that it can be used to create purpose chains from a root time-limited protector.

  • Protect(byte[] plaintext, DateTimeOffset expiration) : byte[]Protect(byte[] plaintext, DateTimeOffset expiration) : byte[]

  • Protect(byte[] plaintext, TimeSpan lifetime) : byte[]Protect(byte[] plaintext, TimeSpan lifetime) : byte[]

  • Protect(byte[] plaintext) : byte[]Protect(byte[] plaintext) : byte[]

  • Protect(string plaintext, DateTimeOffset expiration) : stringProtect(string plaintext, DateTimeOffset expiration) : string

  • Protect(string plaintext, TimeSpan lifetime) : stringProtect(string plaintext, TimeSpan lifetime) : string

  • Protect(string plaintext) : stringProtect(string plaintext) : string

평문만 전달하는 핵심 Protect 메서드와 페이로드의 만료 일자를 지정할 수 있는 새로운 오버로드 메서드가 함께 제공됩니다.In addition to the core Protect methods which take only the plaintext, there are new overloads which allow specifying the payload's expiration date. 만료 일자는 절대 일시 (``DateTimeOffset형식으로) 또는 상대적 시간으로 (현재 시스템 시간에 대한TimeSpan` 형식으로) 지정할 수 있습니다.The expiration date can be specified as an absolute date (via a DateTimeOffset) or as a relative time (from the current system time, via a TimeSpan). 만료가 지정되지 않은 오버로드 메서드가 호출되면 페이로드가 만료되지 않는 것으로 간주됩니다.If an overload which doesn't take an expiration is called, the payload is assumed never to expire.

  • Unprotect(byte[] protectedData, out DateTimeOffset expiration) : byte[]Unprotect(byte[] protectedData, out DateTimeOffset expiration) : byte[]

  • Unprotect(byte[] protectedData) : byte[]Unprotect(byte[] protectedData) : byte[]

  • Unprotect(string protectedData, out DateTimeOffset expiration) : stringUnprotect(string protectedData, out DateTimeOffset expiration) : string

  • Unprotect(string protectedData) : stringUnprotect(string protectedData) : string

Unprotect 메서드는 보호가 해제된 원본 데이터를 반환합니다.The Unprotect methods return the original unprotected data. 페이로드가 아직 만료되지 않았다면 보호되지 않은 원본 데이터와 함께 절대 만료일시가 선택적 out 매개 변수를 통해서 함께 반환됩니다.If the payload hasn't yet expired, the absolute expiration is returned as an optional out parameter along with the original unprotected data. 반면 이미 페이로드가 만료됐다면 모든 Unprotect 오버로드 메서드가 CryptographicException을 던집니다If the payload is expired, all overloads of the Unprotect method will throw CryptographicException.

경고

장기 또는 무기한 유지 해야 하는 페이로드를 보호 하기 위해 이러한 Api를 사용 하는 것에 권장 되지 않습니다.It's not advised to use these APIs to protect payloads which require long-term or indefinite persistence. "I 손실을 수용할 수 있는 한 달 후 영구적으로 복구할 수 없게 하려면 보호 된 페이로드"?"Can I afford for the protected payloads to be permanently unrecoverable after a month?" 가장 좋은 방법은 차단한; 역할도 할 수 있습니다. 대답 한 경우 다음 개발자는 대체 Api를 고려해 야 합니다.can serve as a good rule of thumb; if the answer is no then developers should consider alternative APIs.

다음 예제는 데이터 보호 시스템의 인스턴스를 생성하기 위해서 비-DI 코드 경로를 사용합니다.The sample below uses the non-DI code paths for instantiating the data protection system. 이 예제를 실행하려면, 먼저 Microsoft.AspNetCore.DataProtection.Extensions 패키지 참조를 추가해야 합니다.To run this sample, ensure that you have first added a reference to the Microsoft.AspNetCore.DataProtection.Extensions package.

using System;
using System.IO;
using System.Threading;
using Microsoft.AspNetCore.DataProtection;
 
public class Program
{
    public static void Main(string[] args)
    {
        // create a protector for my application
 
        var provider = DataProtectionProvider.Create(new DirectoryInfo(@"c:\myapp-keys\"));
        var baseProtector = provider.CreateProtector("Contoso.TimeLimitedSample");
 
        // convert the normal protector into a time-limited protector
        var timeLimitedProtector = baseProtector.ToTimeLimitedDataProtector();
 
        // get some input and protect it for five seconds
        Console.Write("Enter input: ");
        string input = Console.ReadLine();
        string protectedData = timeLimitedProtector.Protect(input, lifetime: TimeSpan.FromSeconds(5));
        Console.WriteLine($"Protected data: {protectedData}");
 
        // unprotect it to demonstrate that round-tripping works properly
        string roundtripped = timeLimitedProtector.Unprotect(protectedData);
        Console.WriteLine($"Round-tripped data: {roundtripped}");
 
        // wait 6 seconds and perform another unprotect, demonstrating that the payload self-expires
        Console.WriteLine("Waiting 6 seconds...");
        Thread.Sleep(6000);
        timeLimitedProtector.Unprotect(protectedData);
    }
}
 
/*
 * SAMPLE OUTPUT
 *
 * Enter input: Hello!
 * Protected data: CfDJ8Hu5z0zwxn...nLk7Ok
 * Round-tripped data: Hello!
 * Waiting 6 seconds...
 * <<throws CryptographicException with message 'The payload expired at ...'>>

 */